1 概述
springmvc是基于spring的一个servlet升级版,实际上是spring的一个模块,专门做web开发的。
web开发底层是servlet,框架是在servlet基础上面增加一些功能,让你做web开发方便。
SpringMVC就是一个spring容器,放的是控制器对象(Controller)。我们要做的就是使用@Controller创建控制器对象,把对象放入springmvc容器中,把创建的对象作为控制器使用,这个控制器对象能接受用户的请求,显示处理结果,就当作是一个servlet使用。
使用@Controller创建的是一个普通类对象,不是servlet。springmvc赋予了控制器对象一些额外的功能。
web开发底层是servlet,springmvc中有一个对象是servlet:DispatcherServlet。
DispatcherServlet:负责接收用户的所有请求,用户吧请求给了DispatcherServlet,之后DispatcherServlet把请求转发给我们的Controller对象,最后是Controller对象处理请求。
1.1 简介
SpringMVC又称Spring Web MVC。是spring框架的一部分。
1.2 优点
-
基于MVC架构:功能分工明确。解耦合
-
容易理解,上手快,使用简单:SpringMVC是轻量级的,可以快速开发一个注解的SpringMVC项目。
-
作为Spring框架的一部分,能够使用Spring的IoC和Aop。方便整合其他框架
-
SpringMVC强化注解的使用,在控制器,Service,Dao都可以使用注解,方便灵活。
1.3 第一个注解的SpringMVC项目
1.3.1 新建web maven工程
这次我们创建的maven-apache-webapp骨架的项目
1.3.2 加入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
</dependencies>
1.3.3 *调度器(DispatcherServlet)
-
DispatcherServlet叫做*调度器,是一个servlet,它的父类是集成HttpServlet
-
DispatcherServlet也叫做前端控制器(front controller)
-
负责创建springmvc容器对象,读取xml配置文件,创建文件中的Controller对象
-
DispatcherServlet负责接收用户提交的请求,调用其他的自定义控制器对象,并把请求的处理结果显示给用户
*调度器(DispatcherServlet)的配置:
在web.xml中配置servlet信息
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 声明,注册springMvc的核心对象DispatcherServlet -->
<!--
需要在tomcat服务器启动时,创建DispatcherServlet对象的实例
为什么要创建实例:
因为DispatcherServlet在它创建过程中,会同时创建springMvc的容器对象,
读取springMvc的配置文件,把这个配置文件中的对象都创建好,当用户发起请求时就可以直接使用对象
servlet的初始化会执行init()方法,DispatcherServlet在init()中 {
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入ServletContext中
getServletContext().serAttribute(key,ctx);
}
springMvc创建对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml
我们可以自定义读取配置文件的位置
-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 自定义读取配置文件的位置 -->
<init-param>
<!-- springMvc的配置文件的属性 -->
<param-name>contextConfigLocation</param-name>
<!-- springMvc的配置文件的自定义位置 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 在tomcat启动后,创建Servlet对象 -->
<!--
load-on-startup:表示tomcat在启动后就创建对象的顺序
它的值是大于等于0的整数,值越小创建时间越早。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<!--
使用框架时,url-pattern可以使用两种值
1. 使用扩展名方式,语法*.xxx, xxx是自定义的扩展名。常用方式*.do, *.action, *.mvc等等
凡是使用这种扩展名的请求都交给*调度器管理
2. 使用斜杠"/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
1.3.4 创建发送请求的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>第一个springmvc项目</p>
<p><a href="some.do">发起some.do请求</a></p>
</body>
</html>
1.3.5 创建控制器类(Controller)
-
在类的上面加入@Controller注解,创建对象,并放入到springmvc容器中
-
在类中的方法上面加入@RequestMapping注解
package com.pjh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @Controller 创建处理器对象,对象放在springmvc容器中
* 位置:类之上
* 和spring中讲的@Service,@Component差不多
*
* 能处理请求的都是控制器(处理器)
*/
@Controller
public class MyController {
/*
处理用户提交的请求,springmvc中是使用方法来处理的。
方法是自定义的,可以有多种返回值,多种参数,方法名称自定义
*/
/**
* 准备使用doSome方法处理some.do请求
* @RequestMapping 请求映射,作用是把一个请求地址和一个方法绑定在一起。一个请求指定一个方法处理
* 属性:1. value是一个String,表示请求的uri地址
* value值必须是唯一的,不能重复。在使用时,推荐地址以"/"开头
* value值可以用花括号括起多个地址,在访问这些地址时,都是请求的该方法
* 位置:1. 在方法的上面,常用
* 2. 在类上面使用
* 说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法
* 使用@RequestMapping是可以处理请求的,类似于Servlet中的doGet和doPost
* @return ModelAndView
* Model:数据,请求处理完成后,要显示给用户的数据
* View:视图,比如jsp
*/
@RequestMapping(value = {"/some.do", "/first.do"})
public ModelAndView doSome() {
//创建返回mv对象
ModelAndView mv = new ModelAndView();
//添加数据,框架在请求最后把数据放入到request作用域
//request.setAttribute()
mv.addObject("msg", "some.do请求已处理,来自SpringMVC");
mv.addObject("fun", "执行的doSome方法");
//指定视图,完整路径
//框架对视图执行的forward操作,即
//request.getRequestDispather().forward()
//mv.setViewName("/show.jsp");
//当配置视图解析器后,可以使用逻辑名称(文件名字),指定视图路径
//框架会使用视图解析器的前缀+逻辑名称+后缀 组成完整路径,这里是字符串连接操作
mv.setViewName("show");
//返回mv
return mv;
}
}
1.3.6 创建显示结果的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>show.jsp获得的结果</h3><br/>
<h3>msg:${msg}</h3><br/>
<h3>fun:${fun}</h3>
</body>
</html>
1.3.7 创建springmvc的配置文件(spring的配置文件一样)
-
声明组件扫描器,指定@Controller注解所在的包名
-
声明视图解析器,帮助处理视图的。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明组件扫描器 -->
<context:component-scan base-package="com.pjh.controller"/>
<!-- 声明视图解析器,帮助开发人员设置视图文件的路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀:视图文件的路径 -->
<property name="prefix" value="/WEB-INF/view/"/>
<!-- 后缀:视图文件的拓展名 -->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
1.3.8 分析springmvc请求的发送过程
-
发起some.do
-
tomcat ( Web.xml ---- url-pattern知道*.do的请求发送给DispatcherServlet )
-
DispatcherServlet ( 根据springmvc.xml配置知道some.do ---- doSome方法 )
-
DispatcherServlet把some.do转发给MyController.doSome()方法
-
框架执行doSome()把得到ModelAndView进行处理,转发到show.jsp
1.3.9 分析springmvc执行过程
-
tomcat启动,创建springmvc容器:核心在于DispatcherServlet的init方法,他会创建一个spring容器并且把它加入到ServletContext中成为全局变量
-
请求的处理过程:核心方法是DispatcherServlet的doDispatch方法,它会调用请求对应控制器中的对应方法
2 注解式开发
2.1 @RequestMapping
2.1.1 在类的上方使用
属性value中,写所有请求地址的公共部分,叫做模块名称。
2.1.2 method属性
可以设置请求的方式:GET、POST等
它的值是RequestMethod的枚举值,例如:
表示get请求方式,RequestMethod.GET; 表示post请求方式,RequestMethod.POST;
@RequestMapping(value = {"/some.do", "/first.do"}, method = RequestMethod.GET) @RequestMapping(value = {"/other.do", "/second.do"}, method = RequestMethod.POST)
没有设置该属性时,访问目标方法没有限制。
2.2 控制器处理用户参数
-
为方法增加上HttpServletRequest、HttpServletResponse、HttpSession的形参
-
直接为方法增加上请求中携带的请求参数
2.2.1 逐个接收参数
package com.pjh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class MyController {
/**
* 逐个接收请求参数:
* 要求:处理器方法的形参名与请求中的参数名必须一致,
* 同名参数赋值给同名形参
* 框架接收请求参数:
* 1. 使用request对象接收请求参数
* String strName = request.getParameter("name");
* String strAge = request.getParameter("age");
* 2. springMVC框架通过DisPatcherServlet 调用 MyController的doReceiveProperty()方法
* 调用方法时,按名称对应,把接收的参数赋值给形参
* doReceiveProperty(strName, Integer.parseInt(strAge))
* 框架会提供类型转换的功能,能把字符串转为int,long,float等
*/
@RequestMapping(value = "/receiveproperty.do")
public ModelAndView doReceiveProperty(String name, int age) {
//可以在方法中直接使用name,age
ModelAndView mv = new ModelAndView();
mv.addObject("myname", name);
mv.addObject("myage", age);
mv.setViewName("show");
return mv;
}
}
注意:
-
在框架进行类型转换时,可能出现无法转换的情况,例如age为空时和age不为整数时,这时服务器会阻止请求调用方法,可以用Integer替换形参int,来避免为空的情况
-
如果采用post请求方式,输入中文参数会出现乱码,这时需要手动设置response的encoding为utf-8,如果存在多个方法,可能就要设置多次,这时可以采用过滤器来解决重复代码。 过滤器可以自定义,也可以使用框架自带的 CharacterEncodingFilter。 在web.xml中声明字符编码过滤器:
<!-- 注册声明过滤器,解决post乱码问题 --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 设置项目中使用的字符编码 --> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <!-- 强制请求对象,使用该编码 --> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <!-- 强制应答对象,使用该编码 --> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
如果请求中的参数名和形参名称不一致,就不能得到对应的参数值,从而抛出异常。所以为了解决请求中参数名形参名不一样的问题,我们引入@RequestParam注解。
/** * 请求中参数名和形参名不一样 * @RequestParam 解决请求中参数名形参名不一样的问题 * 属性: * 1. value 请求中的参数名 * 2. required 是一个boolean,默认是true * 表示请求中必须包含此参数 * 位置:在处理器方法的形参定义的前面 */ @RequestMapping(value = "/receiveparam.do") public ModelAndView doReceiveParam(@RequestParam(value="rname", required = false) String name,@RequestParam(value = "rage", required = false) int age) { //可以在方法中直接使用name,age ModelAndView mv = new ModelAndView(); mv.addObject("myname", name); mv.addObject("myage", age); mv.setViewName("show"); return mv; }
2.2.2 对象参数接收
package com.pjh.controller;
import com.pjh.vo.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MyController {
/**
* 处理器方法形参是java对象,这个对象的属性名和请求中的参数名一样
* 框架会创建形参的java对象,给属性赋值,请求中的参数是name,框架会调用setName()
* 形参可以有多个对象或者值,框架会根据请求参数,自动为形参对象创建对象并赋值
*/
@RequestMapping(value = "/receiveobject.do")
public ModelAndView doReceiveObject(Student student) {
ModelAndView mv = new ModelAndView();
mv.addObject("myname", student.getName());
mv.addObject("myage", student.getAge());
mv.addObject("mystudent", student);
mv.setViewName("show");
return mv;
}
}
注意:使用对象参数接收,@RequestParam没有任何效果
2.3 处理器方法的返回值
2.3.1 ModelAndView
Model储存要返回的数据,最后存到resquest里面;View储存要转发的页面,使用forward。
如果当前请求既要返回数据,又要跳转页面,使用MV是非常合适的。
但是如果只需要其中一部分(Model或者View),就有些多余了。
2.3.2 String
如果只是要跳转页面,返回String是最恰当的。
如果没有@ResponseBody注解,字符串表示视图名称。
package com.pjh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class MyController {
/**
* 处理器方法返回String——表示逻辑视图名称,需要配置视图解析器
*/
@RequestMapping("/returnString-view.do")
public String doReturnview(HttpServletRequest request, String name, Integer age) {
System.out.println("myName: " + name + " myAge: " + age);
//可以自己手动添加数据到request
request.setAttribute("myname", name);
request.setAttribute("myage", age);
//show 逻辑视图名称,需要项目中配置了视图解析器
//框架对视图执行forward转发操作
return "show";
}
/**
* 处理器方法返回String——表示完整视图名称,此时不能配置视图解析器
*/
@RequestMapping("/returnString-view.do")
public String doReturnview2(HttpServletRequest request, String name, Integer age) {
System.out.println("myName: " + name + " myAge: " + age);
//可以自己手动添加数据到request
request.setAttribute("myname", name);
request.setAttribute("myage", age);
//完整视图路径,项目中不能配置视图解析器
//框架对视图执行forward转发操作
return "/WEB-INF/view/show.jsp";
}
}
如果有@ResponseBody注解,字符串表示数据。
文件的格式datatype应该是text/plain,此时要自行设置响应头的编码集:
@RequestMapping(value = "...", produces="text/plain;charset=utf-8")
2.3.3 void
不能表示数据,也不能表示视图。
在处理ajax的时候可以使用void返回值。通过Responce输出数据。响应ajax请求。
ajax请求服务端返回的就是数据,和视图无关。
2.3.4 对象Object
这个Object可以是Integer、String、自定义对象、Map、List等,但是不能是逻辑视图。可以使用这个对象表示的数据,响应ajax请求。
ajax主要接收json的数据格式:
-
首先需要加入依赖,springmvc默认使用jackson
-
在springmvc的配置文件中加入<mvc:annotation-driven>注解驱动
注意:此处的annotation-driven一定选择mvc的
-
在处理器上面加上@ResponseBody注解
/** * @ResponseBody * 作用:把处理器方法返回对象转为json后,通过httpServletResponse输出给浏览器 * 位置:方法的定义上面。和其他注解没有顺序先后关系 * 返回对象框架的处理流程: * 1. 框架会把返回的对象,调用框架中的ArrayList<HttpMessageConverter>中的每个类的canWrite()方法 * 来检查哪个HttpMessageConverter接口的实现类能处理该类型的数据 * 2. 框架会调用实现类的write(),MappingJackson2HttpMessageConverter的write()方法 * 把对象转为json,调用jackson的ObjectMapper实现转为json * 3. 框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成 */ @RequestMapping("/returnObject.do") @ResponseBody public Student doReturnObject(String name, Integer age){ System.out.println("myName: " + name + " myAge: " + age); //处理ajax,使用json做数据的格式 Student student = new Student(); student.setAge(age); student.setName(name); return student; }
内部原理:
-
<mvc:annotation-driven>注解驱动。
注解驱动实现的功能是完成java对象到json,xml,text,二进制等数据格式的转换。
该标签加入配置文件后,会自动创建HttpMessageConverter接口的7个实现类对象,包括
HttpMessageConverter接口:消息转换器
功能:
定义了java转为json,xml等数据格式的方法;这个接口有很多的实现类,这些实现类完成java对象的转换。
查看HttpMessageConverter源码,可以找到下面两个方法,是给控制器类把结果输出给浏览器时使用:
//canWrite:作用检查处理器方法的返回值,能不能转为mediaType表示的数据格式 boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); //write:把处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串 void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
常用的实现类有:StringHttpMessageConverter和MappingJackson2HttpMessageConverter。
-
@ResponseBody注解
放在处理器方法上面,通过Responce输出数据,响应ajax请求的。
注意:
-
返回List对象时,是转换成json数组再传递给浏览器
2.4 *调度器中的url-pattern
tomcat本身能够处理静态资源的访问,例如html、image、js文件等。
这源于tomcat的web.xml文件有一个servlet名称是default,在服务器启动时自动创建。
它能被所有web应用使用,主要服务于静态资源文件,能够处理所有未被映射(mapping)的请求。
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
注意,default的mapping用的是斜杠"/",这就表示静态资源文件和未被映射的请求都由这个default处理。
如果,在自己的项目中的*调度器中url-pattern标签中使用斜杠,会替代tomcat提供的default servlet。这就导致所有对静态资源的访问都交给*调度器处理,但是一般情况下,它不能够处理静态资源,没有控制器对象能够处理静态资源的访问。
如果使用了斜杠,那么我们需要处理静态资源的访问请求,有两种方式:
-
需要在springmvc配置文件中加入<mvc:default-servlet-handler/>。
原理是,在加入这个标签之后,控制器会创建一个DefaultServletRequestHandler的处理器对象。
DefaultServletRequestHandler处理器对象:可以把接收的请求转发给tomcat的default这个servlet。
但是这个标签和@RequestMapping注解有冲突,所以需要加入注解驱动(见2.3.4)来解决冲突。
-
在配置文件中加入<mvc:resources/>。
原理是,加入后会创建一个ResourceHttpRequestHandler这个处理器对象。
ResourceHttpRequestHandler处理器对象:可以处理对静态资源的访问
标签有两个属性:
mapping:访问静态资源的uri地址,使用通配符**
location:静态资源在你的项目中的目录位置
例如:<mvc:resources mapping="/static/**" location="/static/"/>
2.5 绝对路径与相对路径
地址分类:
-
绝对地址:带有协议名称的是绝对地址,例如百度一下,你就知道
-
相对地址:没有协议开头的,例如user/some.do,/user/some.do。
相对地址不能独立使用,必须有一个参考地址。通过参考地址+相对地址本身才能指定资源。
-
参考地址:在你的页面中,访问地址不加"/"
斜杠的使用:
"/"表示上一级目录
在前端中"/"表示服务器的根目录(localhost),在后端中表示项目的根目录
快记:前端不加"/",后端加"/"。
参考路径:
html中有一个标签<base> 可以指定当前页面中所有请求地址的参考地址,其中设置href属性为参考地址即可;
范例:<base href= "http://localhost:8080/path/">
但是由于项目的根目录可能不同,可以使用一段java代码来获取这个路径:
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
3 SSM整合开发
终于来到了重头戏。
SSM:即SpringMVC + Spring + MyBatis
SpringMVC:视图层,界面层,负责接收请求,显示处理结果的。 Spring:业务层,管理Service,Dao,工具类对象的 MyBatis:持久层,访问数据库的
流程图: 用户发起请求<=>SpringMVC接收<=>Spring中的Service对象<=>MyBatis处理数据
3.1 SSM中容器的关系
SSM整合也叫SSI(IBatis),整合中有容器:
-
第一个SpringMVC容器,管理Controller控制器对象的。
-
第二个Spring容器,管理Service,Dao,工具类对象
我们需要把使用的对象交给合适的容器创建、管理: 把Controller还有Web开发相关的对象交给SpringMVC容器,这些Web用的对象写在Spring配置文件中。 把Service,dao对象定义在Spring的配置文件中,让Spring管理这些对象。
SpringMVC容器和Spring容器是由关系的,关系已经确定好了。 SpringMVC容器时Spring容器的子容器,类似于继承。 在子容器中的Controller可以访问父容器中的Service对象,就可以实现Controller使用Service对象了
3.2 实现一个整合项目
3.2.1 数据库准备
一张名为student的表
3.2.2 新建Maven Web项目
略
3.2.3 加入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
</dependency>
<!-- Spring and SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- Mysql Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Connection Pool Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
3.2.4 写web.xml的文件
-
注册*调度器DispatcherServlet
目的: 创建SpringMVC容器对象,才能创建Controller类对象 创建的是Servlet,才能接收用户的请求
-
注册spring的监听器ContextLoaderListener
目的: 创建Spring的容器对象,才能创建Service,Dao等对象
-
注册字符集过滤器
目的: 解决post请求乱码问题
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- *调度器 -->
<servlet>
<servlet-name>myWeb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myWeb</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- Spring监听器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- post乱码解决方案,设置过滤器修改编码集 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3.2.5 创建包
-
Controller包
-
Service包
-
Dao包
-
实体类(domain)包
3.2.6 配置文件
-
SpringMVC的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- SpringMVC配置文件 --> <!-- 组件扫描器 --> <context:component-scan base-package="com.pjh.controller"/> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view"/> <property name="suffix" value=".jsp"/> </bean> <!-- 注解解析器 --> <mvc:annotation-driven/> </beans>
-
Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- Spring配置文件 --> <!-- 声明属性文件位置 --> <context:property-placeholder location="classpath:conf/jdbc.properties"/> <!-- 声明druid数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxActive" value="${jdbc.max}"/> </bean> <!-- 声明sqlFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:conf/mybatis.xml"/> </bean> <!-- Mybatis的映射文件扫描器,用于创建dao对象 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.pjh.dao"/> </bean> <!-- 声明service的注解所在的包名位置 --> <context:component-scan base-package="com.pjh.service"/> <!-- 声明事务配置 --> </beans>
-
MyBatis的主配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 提示日志 --> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!-- 别名 --> <typeAliases> <!-- name:实体类所在包名 --> <package name="com.pjh.domain"/> </typeAliases> <!-- sql mapper的位置 --> <mappers> <package name="com.pjh.dao"/> </mappers> </configuration>
-
数据库的属性配置文件
略
3.2.7 写代码
略
3.2.8 写页面
略
3.2.9 项目结构
4 SpringMVC核心技术
4.1 请求重定向和转发
在SpringMVC中,对请求转发和重定向进行了简化,只需要在setViewName()指定的视图前添加forward(转发)或redirect(重定向)的字段。他们有一个共同的特点:不和视图解析器合作。
总所周知:
请求转发是在服务器内进行请求的转发,只有一次请求响应过程,因此可以访问WEB-INF中被保护的资源; 重定向是将请求发回给用户浏览器再访问资源,是两次请求响应过程,因此不能访问WEB-INF中的资源。
关于重定向:
框架会把Model中的简单类型数据,转成String使用,作为get请求参数使用。目的是在重定向之间的两个请求之间传递数据;
因此可以在第二个请求目标使用参数集合对象,得到请求中的参数。
4.2 异常处理
以前我们使用try/catch来处理异常,往往会出现大量的冗余的try/catch代码段,操作繁琐且代码凌乱。
现在框架为你提供了简介的处理异常的方式:
框架采用的是统一,全局的异常处理。把controller中的所有异常处理都集中到一个地方。采用的是aop的思想。把业务逻辑和异常处理代码分开。解耦合。
使用两个注解:
-
@ExceptionHandler
-
@ControllerAdvice
package com.pjh.handler; import com.pjh.exception.AgeException; import com.pjh.exception.NameException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; /** * @ControllerAdvice 控制器增强(给控制器类增加功能--异常处理功能) * 位置:在类的上面 * 特点:需要在配置文件中加入组件扫描器 * @author yueyinghaibao * @date 2021/10/23 */ @ControllerAdvice public class ClobalExceptionHandler { /** * @ExceptionHandler (value = 异常的class) 表示异常的类型,当发生这个类型的异常时,由当前方法处理 */ @ExceptionHandler(value = NameException.class) public ModelAndView doNameException(Exception e) { /* 异常发生处理逻辑: 1. 需要把异常记录下来,到数据库,日志文件 2. 发送通知,把异常信息通过邮件,短信,微信发送给相关人员 3. 给用户友好的提示 */ ModelAndView mv = new ModelAndView(); mv.addObject("msg", "姓名不能为空"); mv.addObject("ex", e); mv.setViewName("error"); return mv; } @ExceptionHandler(value = AgeException.class) public ModelAndView doAgeException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "年龄不能为空"); mv.addObject("ex", e); mv.setViewName("error"); return mv; } /** * 处理其他不知名的异常 */ @ExceptionHandler public ModelAndView doOtherException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "发生错误"); mv.addObject("ex", e); mv.setViewName("error"); return mv; } }
4.3 拦截器
-
拦截器是SpringMVC中的一种,需要实现HandlerIntercepter接口
-
拦截器给过滤器类似,功能方向侧重点不同。过滤器是用来过滤请求参数的,设置编码字符集等工作。 拦截器是拦截用户的请求,做请求要做判断处理的。
-
拦截器是全局的,可以对多个Controller做拦截。 一个项目种可以由0个或多个拦截器,一起拦截用户的请求。 拦截器常用在:用户登陆处理,权限检查,记录日志。
一个过滤器可以拦截多个用户请求,也是aop思想
使用步骤:
-
定义类实现HandlerInterceptor接口
-
在springmvc配置文件中,声明拦截器,让框架知道拦截器的存在
拦截器的执行时间:
-
在请求处理之前,也就是controller类中的方法执行之前先被拦截。
-
在控制器方法执行之后也会执行拦截器
-
在请求处理完成后也会执行拦截器