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对象处理请求。
SpringMVC又称Spring Web MVC。是spring框架的一部分。
基于MVC架构:功能分工明确。解耦合
容易理解,上手快,使用简单:SpringMVC是轻量级的,可以快速开发一个注解的SpringMVC项目。
作为Spring框架的一部分,能够使用Spring的IoC和Aop。方便整合其他框架
SpringMVC强化注解的使用,在控制器,Service,Dao都可以使用注解,方便灵活。
这次我们创建的maven-apache-webapp骨架的项目
<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>
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>
<%@ 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>
在类的上面加入@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; } }
<%@ 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>
声明组件扫描器,指定@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>
发起some.do
tomcat ( Web.xml ---- url-pattern知道*.do的请求发送给DispatcherServlet )
DispatcherServlet ( 根据springmvc.xml配置知道some.do ---- doSome方法 )
DispatcherServlet把some.do转发给MyController.doSome()方法
框架执行doSome()把得到ModelAndView进行处理,转发到show.jsp
tomcat启动,创建springmvc容器:核心在于DispatcherServlet的init方法,他会创建一个spring容器并且把它加入到ServletContext中成为全局变量
请求的处理过程:核心方法是DispatcherServlet的doDispatch方法,它会调用请求对应控制器中的对应方法
属性value中,写所有请求地址的公共部分,叫做模块名称。
可以设置请求的方式: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)
没有设置该属性时,访问目标方法没有限制。
为方法增加上HttpServletRequest、HttpServletResponse、HttpSession的形参
直接为方法增加上请求中携带的请求参数
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; }
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没有任何效果
Model储存要返回的数据,最后存到resquest里面;View储存要转发的页面,使用forward。
如果当前请求既要返回数据,又要跳转页面,使用MV是非常合适的。
但是如果只需要其中一部分(Model或者View),就有些多余了。
如果只是要跳转页面,返回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")
不能表示数据,也不能表示视图。
在处理ajax的时候可以使用void返回值。通过Responce输出数据。响应ajax请求。
ajax请求服务端返回的就是数据,和视图无关。
这个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数组再传递给浏览器
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/"/>
地址分类:
绝对地址:带有协议名称的是绝对地址,例如百度一下,你就知道
相对地址:没有协议开头的,例如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() + "/";
终于来到了重头戏。
SSM:即SpringMVC + Spring + MyBatis
SpringMVC:视图层,界面层,负责接收请求,显示处理结果的。 Spring:业务层,管理Service,Dao,工具类对象的 MyBatis:持久层,访问数据库的
流程图: 用户发起请求<=>SpringMVC接收<=>Spring中的Service对象<=>MyBatis处理数据
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对象了
一张名为student的表
略
<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>
注册中央调度器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>
Controller包
Service包
Dao包
实体类(domain)包
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>
数据库的属性配置文件
略
略
略
在SpringMVC中,对请求转发和重定向进行了简化,只需要在setViewName()指定的视图前添加forward(转发)或redirect(重定向)的字段。他们有一个共同的特点:不和视图解析器合作。
总所周知:
请求转发是在服务器内进行请求的转发,只有一次请求响应过程,因此可以访问WEB-INF中被保护的资源; 重定向是将请求发回给用户浏览器再访问资源,是两次请求响应过程,因此不能访问WEB-INF中的资源。
关于重定向:
框架会把Model中的简单类型数据,转成String使用,作为get请求参数使用。目的是在重定向之间的两个请求之间传递数据;
因此可以在第二个请求目标使用参数集合对象,得到请求中的参数。
以前我们使用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; } }
拦截器是SpringMVC中的一种,需要实现HandlerIntercepter接口
拦截器给过滤器类似,功能方向侧重点不同。过滤器是用来过滤请求参数的,设置编码字符集等工作。 拦截器是拦截用户的请求,做请求要做判断处理的。
拦截器是全局的,可以对多个Controller做拦截。 一个项目种可以由0个或多个拦截器,一起拦截用户的请求。 拦截器常用在:用户登陆处理,权限检查,记录日志。
一个过滤器可以拦截多个用户请求,也是aop思想
使用步骤:
定义类实现HandlerInterceptor接口
在springmvc配置文件中,声明拦截器,让框架知道拦截器的存在
拦截器的执行时间:
在请求处理之前,也就是controller类中的方法执行之前先被拦截。
在控制器方法执行之后也会执行拦截器
在请求处理完成后也会执行拦截器