0 、概述 服务器端分成三层架构。
一、环境搭建 1.1 Maven环境的创建
导入坐标依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <spring.version > 5.0.2.RELEASE</spring.version > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > <scope > provided</scope > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.0</version > <scope > provided</scope > </dependency > </dependencies >
配置核心的控制器(类似servlet类 – dispatcherServlet)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app > <display-name > Archetype Created Web Application</display-name > <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
当<url-pattern>/</url-pattern>时,默认就是拦截所有路径连静态资源也不能访问。但是Controller中配置@RequestMapping的路径是不会被拦截的,配置了@RequestMapping就相当于在web.xml中注<servlet>。
1.2 第一个执行程序 1.2.1 引入SpringMVC配置文件 在resources下新建springMVC.XML配置文件:
1 2 3 4 5 6 7 8 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:mvc ="http://www.springframework.org/schema/mvc" xmlns:context ="http://www.springframework.org/schema/context" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" ></beans >
1.2.2 编写控制器 1 2 3 4 5 6 7 8 9 10 @Controller public class HelloController { @RequestMapping ("/hello" ) public String sayHello () { System.out.println("Hello SpringMVC" ); return "success" ; } }
控制器类配置@Controller注解,表明是控制器。
在具体的方法上配置@RequestMapping注解,参数即为访问时的资源路径
return中的字符串,方法执行完需要跳转的页面
1.2.3 完善springMVC.xml配置文件
控制器中加入注解,那么就需要配置需要扫描的包;
配置文件解析器,创建IOC容器对象,由Tomcat负责调用;
配置spring开启注解MVC的支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:mvc ="http://www.springframework.org/schema/mvc" xmlns:context ="http://www.springframework.org/schema/context" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="cn.lizhi" > </context:component-scan > <bean id ="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/pages/" > </property > <property name ="suffix" value =".jsp" > </property > </bean > <mvc:annotation-driven > </mvc:annotation-driven > </beans >
WEB-INF目录下的内容是对客户端不可见,只对服务端可见,即客户端不能直接对其进行访问。
1.2.4 完善web.xml配置文件 由于上方的springMVC.XML配置文件时在resources目录下的,我们启动的是web项目,就需要将该配置文件加载进Tomcat服务器进行读取。
即:配置Servlet的初始化参数,读取springMVC的配置文件,创建spring容器,用于加载配置文件。
当MVC配置文件加载成功,那么其中的扫描就能够成功,继而将控制器中的类加载成对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app > <display-name > Archetype Created Web Application</display-name > <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springMVC.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
二、Spring MVC 详解 2.1 执行过程及组件分析 2.1.1 执行过程
当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件。这里是服务器启动,应用被加载。读取到web.xml中的配置创建spring容器并且初始化容器中的对象。
在springmvc.xml配置文件中开启了注解扫描,那么相应的controller对象(HelloController)对象就会被创建。
从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法。浏览器发送请求,被DispatcherServlet捕获,该Servlet并不处理请求,而是把请求转发出去。转发的路径是根据请求URL,匹配@RequestMapping中的内容。
根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件。即:根据方法的返回值,借助InternalResourceViewResolver找到对应的结果视图。
Tomcat服务器渲染页面,做出响应。
2.1.2 组件分析
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于MVC模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlderMapping负责根据用户请求找到Handler,即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
它就是开发中编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理。
Handler:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
View:视图
将数据视图展示给客户端,即用户。
2.1.3 <mvc:annotation-driver>说明 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器成为SpringMVC的三大组件。使用<mvc:annotation-driver>自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器)。
2.2 常用注解说明 2.2.1 RequestMapping 作用:用于建立请求URL和处理请求方法之间的对应关系。
2.2.2 RequestParam 作用:把请求中指定名称的参数给控制器中的形参赋值。(适用于请求名称与属性名不相同的情况)
属性:
value:请求参数的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
1 2 3 4 5 @RequestMapping ("/useRequestParam" )public String useRequestParam (@RequestParam("name" ) String username,@RequestParam (value="age" ,required=false ) Integer age) { System.out.println(username+"," +age); return "success" ; }
2.2.3 RequestBody 作用:用于获取请求体 内容。直接使用得到是key=value&key=value...结构的数据。get请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。当取值是true时,get请求方式会报错。如果取值为false,get请求得到是null。
1 2 3 4 5 @RequestMapping ("/useRequestBody" )public String useRequestBody (@RequestBody(required=false ) String body) { System.out.println(body); return "success" ; }
2.2.4 PathVariable 作用:用于绑定url中的占位符。例如:请求url中 /delete/{id},这个{id}就是url占位符。url支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。
属性:
value:用于指定url中占位符名称。
required:是否必须提供占位符。
重点 :restful风格。
1 2 3 4 5 @RequestMapping ("/usePathVariable/{id}" )public String usePathVariable (@PathVariable("id" ) Integer id) { System.out.println(id); return "success" ; }
作用:用于获取请求消息头
属性:
value:提供消息头名称,用于指定获取消息头中的哪一部分。
required:是否必须有此消息头。
1 2 3 4 5 6 @RequestMapping ("/useRequestHeader" )public String useRequestHeader (@RequestHeader(value="Accept-Language" , required=false ) String requestHeader) { System.out.println(requestHeader); return "success" ; }
将请求头内容的信息封装到requestHeader参数中。
2.2.6 CookieValue 作用:用于把指定cookie名称的值传入控制器方法参数。
属性:
value:指定cookie的名称。键值对的形式,通过键来获取到它的值。
required:是否必须有cookie
1 2 3 4 5 6 @RequestMapping ("/useCookieValue" )public String useCookieValue (@CookieValue(value="JSESSIONID" ,required=false ) String cookieValue) { System.out.println(cookieValue); return "success" ; }
2.2.7 ModelAttribute 作用:该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的key。key可以是POJO的属性名称,也可以是Map结构的key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
当我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据时肯定没有此字段的内容,一旦更新会把该字段内容置为null,此时就可以使用此注解解决问题。
示例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 @ModelAttributepublic public void showModel (User user) { System.out.println("执行了showModel方法" +user.getUsername()); } @RequestMapping ("/testModelAttribute" )public String testModelAttribute (User user) { System.out.println("执行了控制器的方法" +user.getUsername()); return "success" ; }
即先执行showModel方法,再执行控制器中的方法testModelAttribute。
2.2.7.1 ModelAttribute 修饰方法带返回值 需求:修改用户信息,要求用户密码不能修改
前端代码:
1 2 3 4 5 <form action="springmvc/updateUser" method="post" > 用户名称:<input type="text" name="username" ><br/> 用户年龄:<input type="text" name="age" ><br/> <input type="submit" value="保存" > </form>
模拟查询数据库中用户信息
1 2 3 4 5 6 7 @ModelAttribute public User showModel (String username) { User userByName = findUserByName(username); System.out.println("执行了 showModel 方法" +userByName); return userByName; }
模拟修改用户方法
1 2 3 4 5 @RequestMapping ("/updateUser" )public String testModelAttribute (User user) { System.out.println("控制器中处理请求的方法:修改用户:" +user); return "success" ; }
模拟去数据库查询
1 2 3 4 5 6 7 8 private User findUserByName (String username) { User user = new User(); user.setUsername(username); user.setAge(19 ); user.setPassword("123456" ); return user; }
首先通过前端请求,获取username,而在showModel方法中参数,就是由前端请求的参数username。然后showModel方法体中通过数据库查询对象,再将对象进行返回。返回的对象是数据中的相对应的原有对象。(类似过滤器,后续在控制器中将需要修改的值,进行修改,不变的值,就不需要再次改动)。
2.2.7.2 ModelAttribute 修饰方法不带返回值 需求:修改用户信息,要求用户的密码不能修改
前端代码
1 2 3 4 5 6 <!-- 修改用户信息 --> <form action="springmvc/updateUser" method="post" > 用户名称:<input type="text" name="username" ><br/> 用户年龄:<input type="text" name="age" ><br/> <input type="submit" value="保存" > </form>
查询数据库中用户信息– 模拟去数据库查询
1 2 3 4 5 6 7 @ModelAttribute public void showModel (String username,Map<String,User> map) { User user = findUserByName(username); System.out.println("执行了 showModel 方法" +user); map.put("abc" ,user); }
模拟修改用户方法
1 2 3 4 5 @RequestMapping ("/updateUser" )public String testModelAttribute (@ModelAttribute("abc" ) User user) { System.out.println("控制器中处理请求的方法:修改用户:" +user); return "success" ; }
模拟去数据库查询
1 2 3 4 5 6 7 private User findUserByName (String username) { User user = new User(); user.setUsername(username); user.setAge(19 ); user.setPassword("123456" ); return user; }
第二种不带返回值的方式更容易理解,即将原有的对象存放在map集合中,再通过注解,获取指定(根据map中的键)的数据给参数赋值。最后,将前端请求的参数对应的封装到这个参数中,就能够保证这个参数对象的所有属性都能够有值。
2.2.8 SessionAttributes 作用:用于多次执行控制器方法间的参数共享。只能作用在类对象(Class)上。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型
前端代码
1 2 3 4 <!-- SessionAttribute 注解的使用 --> <a href="springmvc/testPut">存入 SessionAttribute</a> <hr/> <a href="springmvc/testGet">取出 SessionAttribute</a> <hr/> <a href="springmvc/testClean">清除 SessionAttribute</a>
控制器中的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Controller ("sessionAttributeController" )@RequestMapping ("/springmvc" )@SessionAttributes (value ={"username" ,"password" },types={Integer.class }) public class SessionAttributeController { @RequestMapping ("/testPut" ) public String testPut (Model model) { model.addAttribute("username" , "泰斯特" ); model.addAttribute("password" ,"123456" ); model.addAttribute("age" , 31 ); return "success" ; } @RequestMapping ("/testGet" ) public String testGet (ModelMap model) { System.out.println(model.get("username" )+";" +model.get("password" )+";" +model.get("a ge" )); return "success" ; } @RequestMapping ("/testClean" ) public String complete (SessionStatus sessionStatus) { sessionStatus.setComplete(); return "success" ; } }
通过model对象进行值的存储操作,底层会将值存储在request域中。而又使用@SessionAttributes注解,具体有@SessionAttributes(value ={"username","password"},types={Integer.class})。此时通过values数组的指定 – username、password,则表明model在存储操作时,不仅会将这两个的值存储在request域对象中,同时也会存储在session域对象中。
取值时,使用的model实现类 – ModelMap。
删除时,使用SessionStatus。
2.3 请求参数的绑定 前端向后端进行请求时,表单中请求参数都是基于key=value的。SpringMVC绑定请求参数的过程是通过把表单请求参数,作为控制器中方法参数进行绑定的。
2.3.1 支持的数据类型
基本数据类型
POJO类型参数(实现序列化接口)
数组和集合类型参数
包括List结构和Map结构的集合(包括数组)
SpringMVC绑定请求参数是自动实现的,但是想要使用,必须遵循使用要求。
2.3.2 使用要求
基本数据类型或者是String类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致 。(严格区分大小写)
POJO类型或者及其关联对象
如果表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。
如果是集合类型
SpringMVC可以实现一些数据类型自动转换。其内置转换器全部都在:
org.springframework.core.convert.support包下。
2.3.3 使用实例 2.3.3.1 POJO类型作为参数
实体类代码
1 2 3 4 5 6 7 8 9 10 11 public class Account implements Serializable { private Integer accountId; private String accountName; private Float money; private Address address; }
以上是Account类。其中关联Address类:
1 2 3 4 5 6 7 8 9 10 11 package cn.lizhi.domain;public class Address { private String provinceName; private String cityName; }
前端代码
1 2 3 4 5 6 7 <form action="account/saveAccount" method="post" > 账户名称:<input type="text" name="name" ><br/> 账户金额:<input type="text" name="money" ><br/> 账户省份:<input type="text" name="address.provinceName" ><br/> 账户城市:<input type="text" name="address.cityName" ><br/> <input type="submit" value="保存" > </form>
通过对象.属性的方式进行赋值。
控制器代码
1 2 3 4 5 @RequestMapping ("/saveAccount" )public String saveAccount (Account account) { System.out.println("保存了账户。。。。" +account); return "success" ; }
2.3.3.2 POJO类中包含集合类型参数
实体类 – User类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package cn.lizhi.domain;import java.util.Date;import java.util.List;import java.util.Map;public class User { private String username; private String password; private Integer age; private Date date; private List<Account> accounts; private Map<String,Account> accountMap; @Override public String toString () { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + ", date=" + date + ", accounts=" + accounts + ", accountMap=" + accountMap + '}' ; } }
前端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!-- POJO 类包含集合类型演示 --> <form action="account/updateAccount" method="post" > 用户名称:<input type="text" name="username" ><br/> 用户密码:<input type="password" name="password" ><br/> 用户年龄:<input type="text" name="age" ><br/> 账户 1 名称:<input type="text" name="accounts[0].name" ><br/> 账户 1 金额:<input type="text" name="accounts[0].money" ><br/> 账户 2 名称:<input type="text" name="accounts[1].name" ><br/> 账户 2 金额:<input type="text" name="accounts[1].money" ><br/> 账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/> 账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/> 账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/> 账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/> <input type="submit" value="保存" > </form>
集合、列表赋值的方式。三要素:属性、下标、参数(属性)
控制器代码
1 2 3 4 5 @RequestMapping ("/updateAccount" )public String updateAccount (User user) { System.out.println("更新了账户。。。。" +user); return "success" ; }
2.4 请求参数乱码问题 在tomcat8以后get请求方式,中文正常显示;post请求方式,中文会出现乱码问题。
在之前的serlvet学习中,对乱码解决的方式,是通过Filter过滤器。而现在SpringMVC提供好现有的类供我们使用。
首先post请求方式,在web.xml中配置一个过滤器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <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 > encoding</param-name > <param-value > UTF-8</param-value > </init-param > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
如果想不过滤静态资源,在 Springmvc 的配置文件中可以配置,静态资源不过滤:
1 2 3 4 <mvc:resources location ="/css/" mapping ="/css/**" /> <mvc:resources location ="/images/" mapping ="/images/**" /> <mvc:resources location ="/scripts/" mapping ="/javascript/**" />
get请求方式:
tomcat对GET和POST请求处理方式是不同的,GET请求的编码问题,要改tomcat的server.xml配置文件,如下:
1 2 3 4 5 6 7 8 <Connector connectionTimeout ="20000" port ="8080" protocol ="HTTP/1.1" redirectPort ="8443" />改为: <Connector connectionTimeout ="20000" port ="8080" protocol ="HTTP/1.1" redirectPort ="8443" useBodyEncodingForURI ="true" />useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
2.5 自定义类型转换器 例如,在前端输入日期格式时:
1 2 <!-- 特殊情况之:类型转换问题 --> <a href="account/deleteAccount?date=2018-01-01">根据日期删除账户</a>
可以看出,请求参数中,date=2018-01-01。
当我们在后端接收到请求时:
1 2 3 4 5 @RequestMapping ("/deleteAccount" ) public String deleteAccount (String date) { System.out.println("删除了账户:" + date); return "success" ; }
输出:删除了账户:2018-01-01。如果当我们将接收参数的类型改为Date类型时:
1 2 3 4 5 @RequestMapping ("/deleteAccount" ) public String deleteAccount (Date date) { System.out.println("删除了账户:" + date); return "success" ; }
此时,前端再次请求时,会报400。
下面便是我们自定义类型转化的方式:
首先,定义一个类,实现Convertet接口,该接口有两个泛型。
1 2 3 4 5 6 7 public interface Converter <S , T > { @Nullable T convert (S source) ; }
其中,S表示接受的类型,T表示目标类型。
其实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class StringToDate implements Converter <String , Date > { @Override public Date convert (String source) { if (source == null || source == "" ) { throw new RuntimeException("请输入日期" ); } SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd" ); try { Date data = format.parse(source); return data; } catch (ParseException e) { throw new RuntimeException("请输入正确的日期格式" ); } } }
其次,在Spring配置文件中配置类型转换器。
Spring配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="converterService" class ="org.springframework.context.support.ConversionServiceFactoryBean" > <property name ="converters" > <array > <bean class ="cn.lizhi.utils.StringToDate" /> </array > </property > </bean > <mvc:annotation-driven conversion-service ="converterService" > </mvc:annotation-driven >
通过查看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class ConversionServiceFactoryBean implements FactoryBean <ConversionService >, InitializingBean { @Nullable private Set<?> converters; @Nullable private GenericConversionService conversionService; public ConversionServiceFactoryBean () { } public void setConverters (Set<?> converters) { this .converters = converters; } public void afterPropertiesSet () { this .conversionService = this .createConversionService(); ConversionServiceFactory.registerConverters(this .converters, this .conversionService); } protected GenericConversionService createConversionService () { return new DefaultConversionService(); } @Nullable public ConversionService getObject () { return this .conversionService; } public Class<? extends ConversionService> getObjectType() { return GenericConversionService.class ; } public boolean isSingleton () { return true ; } }
其中converters是集合类型,并且有setter方法,通过上方的spring配置文件,给工厂注入一个新的类型转换器(不会覆盖原有的转换器)。
这样,在我们后面的使用中,便能够识别并对应转换成我们相应数据格式。
总之,实现转换器的方法以及对spring的配置,就是在原有的转换器集合中,再加入一种我们自己编写的转换器,以供我们使用。
2.6 响应数据 2.6.1 方法返回值的分类 2.6.1.1 String 类型 Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
即为前面所写的常规的返回值为String的方法,返回值为所需要跳转的物理视图的名称(即为跳转页面名称 –>地址)。
1 2 3 4 5 6 @RequestMapping (value="/hello" ) public String sayHello () { System.out.println("Hello SpringMVC!!" ); return "success" ; }
模拟应用 – 模拟对数据库中的数据进行查询
前端代码
index.jsp页面
1 2 3 <h3 > 修改用户</h3 > <a href ="/user/initUpdate" > 模拟用户修改</a >
模拟update.jsp页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <%@ page contentType ="text/html;charset=UTF-8" language ="java" isELIgnored ="false" %> <html > <head > <title > 首页</title > </head > <body > <h3 > 修改用户</h3 > <form action ="/user/initUpdate" method ="post" > 姓名:<input type ="text" name ="username" value ="${user.username}" > <br > 密码:<input type ="text" name ="password" value ="${user.password}" > <br > 金额:<input type ="text" name ="money" value ="${user.money}" > <br > <input type ="submit" value ="提交" > </form > </body > </html >
后端控制器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Controller ("userController" )@RequestMapping ("/user" )public class UserController { @RequestMapping ("/initUpdate" ) public String initUpdate (Model model) { User user = new User(); user.setUsername("张三" ); user.setPassword("123456" ); user.setMoney(123 d); model.addAttribute("user" , user); return "update" ; } }
返回值是update,即最后跳转到update页面。
2.6.1.2 void类型 如果控制器的方法返回值是void,在执行程序报404的异常,默认查找jsp页面没有找到。
1 2 3 Type Status Report 消息 /WEB-INF/pages/user/initUpdate.jsp 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。
从上面的错误信息可以看出,它会默认跳转到控制器中@RequestMapping("/example")中initUpdate的页面。
在SpringMVC中Servlet原始API可以作为控制器中方法的参数,即在controller方法形参上可以定义request和response,使用request或response指定相应结果。
使用request(即为存储转发)转向页面
1 2 request.getRequestDispatcher("/WEB-INF/pages/success.jsp" ).forward(request, response);
在存储转发中不需要写虚拟目录,但这里的资源路径需要写webApp中的全路径,没有像前面只写一个success的原因是,前一种是交给了视图解析器进行管理;而这里没有用到视图解析器,是单纯由request进行实现,故需要写出资源的全路径。
使用response进行页面的重定向
1 response.sendRedirect(request.getContextPath() + "/page.jsp" );
需要加上虚拟目录。
通过response指定响应结果,例如响应json数据:
1 2 3 response.setCharacterEncoding("utf-8" ); response.setContentType("application/json;charset=utf-8" ); response.getWriter().write("json串" );
2.6.1.3 关键字的转发或重定向 使用关键字进行转发或重定向时,Spring不会再通过视图解析器帮我们解析路径,需要我们自己手动配置。即就像上一小结中,资源路径需要写全。
Forward转发
controller方法在提供了String类型的返回值之后,默认就是请求转发。当然,我们可以手动进行设置:
1 2 3 4 5 @RequestMapping ("/testForward" )public String testForward () { System.out.println("test1方法执行了..." ); return "forward:/WEB-INF/pages/success.jsp" ; }
如果用了forward:,则路径必须写成实际视图url,不能写逻辑视图。
它相当于它相当于request.getRequestDispatcher("**url**").forward(request,response)。使用请求转发,既可以转发到jsp(到视图解析器中),也可以转发到其他的控制器方法。
Redirect重定向
controller方法提供了一个String类型返回值之后,它需要在返回值里使用:redirect:
1 2 3 4 5 6 @RequestMapping ("/testRedirect" ) public String testRedirect () { System.out.println("testRedirect方法执行了..." ); return "redirect:/index.jsp" ; }
它相当于response.sendRedirect(url)。需要注意的是,如果是重定向到jsp页面,则jsp页面不能写在WEB-INF目录中,否则无法找到。
原因: 重定向是客户端的,而转发是服务端内部的。 重定向是让客户端去访问重定向的地址,而WEB-INF下的文件是不能通过外部访问的!
2.6.1.4 ResponseBody响应json数据 作用:该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据。如:json、xml等,通过Response响应给客户端。
需求:使用@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端。
前置:SpringMVC默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包。我们的项目中通过导入依赖的方法进行包的管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.9.0</version > </dependency > <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-annotations</artifactId > <version > 2.9.0</version > </dependency >
需要配置前端控制器不拦截静态资源。
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置:
1 2 3 4 5 6 <mvc:resources location ="/css/" mapping ="/css/**" /> <mvc:resources location ="/images/" mapping ="/images/**" /> <mvc:resources location ="/js/" mapping ="/js/**" />
其中,mvc:resources标签配置不过滤谁。
location元素表示webapp目录下的包下的所有文件.
mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b.
客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中。
响应:将对象转换成json字符串。
前端部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <input type ="button" value ="异步请求测试" id ="testJson" > <script > $(function ( ) { $("#testJson" ).click(function ( ) { $.ajax({ type: "post" , url: "${pageContext.request.contextPath}/user/testResponseBody" , contentType: "application/json;charset=utf-8" , data: '{"username":"张三","password":"123","money":123}' , dataType: "json" , success: function (data) { alert(data) } }); }); }) </script >
控制器中的代码
1 2 3 4 5 @RequestMapping ("/testResponseBody" )public @ResponseBody User testResponseBody (@RequestBody User user) { System.out.println("异步请求:" + user); return user; }
在控制器中的代码,其中@RequestBody将前端发送的ajax请求的json格式数据封装成JavaBean。@ResponseBody将后端返回值JavaBean对象,格式化成json数据类型返回给客户端,直接响应。
总结:首先通过@RequestBody获取请求体数据,将前端请求的json字符穿转换成JavaBean对象,最后使用@ResponseBody注解把JavaBean对面转换成Json字符串,直接响应。
2.6.1.5 ModelAndView对象 ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图,即可以用作控制方法的返回值。该对象中有两个方法:
方法1:addObject
1 2 3 4 public ModelAndView addObject (String attributeName, Object attributeValue) { this .getModelMap().addAttribute(attributeName, attributeValue); return this ; }
添加模型到该对象中,通过上面的代码可以看出,和前面所讲的请求参数封装中用到的对象是同一个。即jsp页面中同样可以使用EL表达式从request域中获取值。
方法2:setViewName
1 2 3 public void setViewName (@Nullable String viewName) { this .view = viewName; }
用于设置逻辑视图名称,视图解析器会根据名称前往指定的视图。这也ModelAndView和Model最大的不同,它可以设置跳转的逻辑视图名称。
使用示例:
1 2 3 4 5 6 7 8 @RequestMapping ("/testModelAndView" )public ModelAndView testModelAndView () { System.out.println("testModelAndView..." ); ModelAndView mv = new ModelAndView(); mv.addObject("username" , "张三" ); mv.setViewName("success" ); return mv; }
可以将对象存储到request域中。mv.addObject("key",value)
可以存储跳转到哪个页面中。mv.setViewName("success") – 选择视图解析器,进行解析。
前端代码:可以直接通过EL表达式进行值的获取,${username} --> 张三。
ModelAndView和Model两者的不同:
Model是每次请求中都存在的默认参数,利用其addAttribute()方法即可将服务器的值传递到jsp页面中;
ModelAndView包含model和view两部分,使用时需要自己实例化,利用ModelMap用来传值,也可以设置view的名称。
总而言之,就是ModelAndView除了同Model一样包含存储的键值外,它还存储着跳转页面的名称地址,直接将ModelAndView对象整体作为返回值,其对象中存储的地址自动由SpringMVC进行视图解析。
2.7 SpringMVC实现文件上传 文件上传的前提:
form表单的enctype取值必须是:multipart/form-data。默认值是:application/x-www-form-urlencoded。enctype:是表单请求正文的类型。
method属性取值必须是POST
提供一个文件选择域<input type="file"/>
文件上传的原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 当form 表单的enctype取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是: key=value&key=value&key=value 当form 表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成: 每一部分都是 MIME 类型描述的正文 -----------------------------7de1a433602ac 分界符 Content-Disposition: form-data; name="userName" 协议头 aaa 协议的正文 -----------------------------7de1a433602ac Content-Disposition: form-data; name="file"; filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt" Content-Type: text/plain 协议的类型(MIME 类型) bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -----------------------------7de1a433602ac--
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:
Commons-fileupload
Commons-io
Commons-io不属于文件上传组件的开发jar文件,但Commons-fileupload组件从1.1版本开始,它工作时需要commons-io包的支持。
导入依赖:
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > commons-fileupload</groupId > <artifactId > commons-fileupload</artifactId > <version > 1.3.1</version > </dependency > <dependency > <groupId > commons-io</groupId > <artifactId > commons-io</artifactId > <version > 2.4</version > </dependency >
前端页面:
1 2 3 4 <form action ="/user/testUpload" method ="post" enctype ="multipart/form-data" > 选择文件:<input type ="file" name ="upload" /> <br > <input type ="button" value ="文件上传" /> </form >
后端页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @RequestMapping ("/testUpload" )public String testUpload (HttpServletRequest request) throws Exception { String path = request.getSession().getServletContext().getRealPath("/uploads" ); File file = new File(path); if (!file.exists()) { file.mkdirs(); } DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload fileUpload = new ServletFileUpload(factory); List<FileItem> list = fileUpload.parseRequest(request); for (FileItem fileItem : list) { if (fileItem.isFormField()) { continue ; } else { String name = fileItem.getName(); String uuid = UUID.randomUUID().toString().replaceAll("-" , "" ).toUpperCase(); name = uuid + "_" + name; fileItem.write(new File(file, name)); fileItem.delete(); } } return "success" ; }
备注:request.getSession().getServletContext()获取servlet容器对象(最大的域对象),也可以理解为项目真正部署到tomcat时获得的tomcat(服务器)对象。因为session是服务器端对象。而request.getSession().getServletContext().getRealPath()用于获取指定目录在服务器端所真正部署的路径。
2.7.1 SpringMVC传统方式的文件上传 SpringMVC传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上,并且上传完成以后,浏览器可能跳转。
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
配置文件解析器
1 2 3 4 5 <bean id ="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name ="maxUploadSize" value ="10485760" /> </bean >
控制器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @RequestMapping ("/testSpringMVCUpload" )public String testSpringMVCUpload (HttpServletRequest request, MultipartFile upload) throws IOException { System.out.println("SpringMVC方式的文件上传.." ); String path = request.getSession().getServletContext().getRealPath("/uploads" ); File file = new File(path); if (!file.exists()) { file.mkdirs(); } String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-" , "" ).toUpperCase(); filename = uuid + "_" + filename; upload.transferTo(new File(path,filename)); return "success" ; }
SpringMVC文件上传的主要步骤图:
首先前端请求,经过前端控制器将请求交给配置文件解析器,由相应的处理器进行处理。
2.7.2 SpringMVC跨服务器方式的文件上传 在实际开发中,我们可能会处理很多不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器
即每个服务器负责每一个功能模块,而不是由一个服务器承担全部。分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。请求都由应用服务器进行处理转发,而需要的功能都分发到每个单独的服务器进行处理。见下图:
现在模拟图片上传:
导入开发需要的Jar包
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > com.sun.jersey</groupId > <artifactId > jersey-core</artifactId > <version > 1.18.1</version > </dependency > <dependency > <groupId > com.sun.jersey</groupId > <artifactId > jersey-client</artifactId > <version > 1.18.1</version > </dependency >
需要在图片服务器上的web.xml添加如下配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <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 > <init-param > <param-name > readonly</param-name > <param-value > false</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet >
即:接收文件的目标服务器可以支持写入操作。
编写应用服务器端的控制器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @RequestMapping ("/testSpringMVCUpload2" )public String testSpringMVCUpload2 (MultipartFile upload) throws IOException { System.out.println("SpringMVC跨服务器上传..." ); String path = "http://localhost:8088/picture/uploads/" ; String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-" , "" ).toUpperCase(); filename = uuid + "_" + filename; Client client = Client.create(); WebResource webResource = client.resource(path + filename); webResource.put(String.class ,upload .getBytes ()) ; return "success" ; }
2.8 SpringMVC的异常处理 系统中的异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。SpringMVC异常处理见下图:
控制器中捕获异常,从下向上抛出异常。
其目的是为了在出现异常的时候,跳到另外一个“友好”页面。模拟应用步骤:
自定义一个异常类。(继承Exception)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package cn.lizhi.other;public class SysException extends Exception { private String message; public SysException (String message) { this .message = message; } public SysException () { } @Override public String getMessage () { return message; } public void setMessage (String message) { this .message = message; } }
编写异常处理器类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class SysExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) { ex.printStackTrace(); SysException sysException = null ; if (ex instanceof SysException) { sysException = (SysException) ex; } else { sysException = new SysException("系统错误,请于管理员联系" ); } ModelAndView mv = new ModelAndView(); mv.addObject("message" , sysException.getMessage()); mv.setViewName("error" ); return mv; } }
即异常处理器,实现接口 HandlerExceptionResolver,其中ex参数表示接收到的异常对象。其中创建的ModelAndView用于存入异常信息,键值对;再设置跳转路径。
这里我们可以通过判断不同的异常类型跳转到不同的页面显示。
bean配置文件中配置异常处理器类。
1 2 <bean id ="handlerExceptionResolver" class ="cn.lizhi.other.SysExceptionResolver" />
模拟出现异常
1 2 3 4 5 6 @RequestMapping ("testException" )public String testException () { System.out.println("模拟异常处理器的处理方式" ); int i = 3 / 0 ; return "success" ; }
页面出现结果 –> 系统错误,请于管理员联系
2.9 SpringMVC中的拦截器 Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺 序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但 是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法 ,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦 截的。
它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
HandlerInterceptor拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。
2.9.1 自定义拦截器步骤
创建类,实现HandlerInterceptor接口,需要重写需要的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器执行了...前" ); return true ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器执行了...后" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("页面跳转完毕后..." ); } }
preHandler
方法是在controller方法执行前,进行拦截的方法;返回结果为true表示放行,返回结果为false表示拦截(配合条件判断使用),因为提供了request、response参数,所以可以使用转发或者重定向直接跳转到指定的页面。
调用:按拦截器定义顺序调用
作用:如果决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是需要业务处理器进行处理,则返回true;如果不需要再调用其他的组件去处理请求,则返回false。
postHandler
后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
按拦截器定义逆序调用;在拦截器链内所有拦截器返回成功后进行调用。
作用:在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,处理ModelAndView中的值。
afterCompletion
调用顺序:按拦截器定义逆序调用
调用时机:对拦截器链内所有拦截器内返回成功的拦截器才调用它的afterCompletion方法。
作用:在业务处理器处理完请求后,但是DispathcerServlet向客户端返回响应前被调用。可以在该方法中进行一些资源清理的操作。
在view视图渲染完毕以后执行,不能再进行页面的跳转。
一旦在preHandler方法中返回了false(等同于出现了异常),后续的拦截器和controller方法就都不会再执行,也不会再执行postHandler方法,只会倒叙执行afterCompletion方法。
拦截器只能拦截Controller中的方法。
在springmvc.xml配置文件中配置拦截器类
1 2 3 4 5 6 7 8 9 10 11 12 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/user/*" /> <bean id ="myInterceptor" class ="cn.lizhi.utils.MyInterceptor" /> </mvc:interceptor > </mvc:interceptors >
可以配置多个拦截器,拦截器执行的顺序就是配置文件中注册的拦截器对象的顺序。
2.9.2 HandlerInterceptor接口中的方法总结
preHandle方法是controller方法执行前拦截的方法
可以使用request或者response跳转到指定的页面
return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
return false不放行,不会执行controller中的方法。
postHandle是controller方法执行后执行的方法,在JSP视图执行前。
可以使用request或者response跳转到指定的页面
如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
postHandle方法是在JSP执行后执行
request或者response不能再跳转页面了
三、SpringMVC扩展 3.0 启动搭建 SpringMVC是Spring的web模块;所有模块的运行都是依赖核心模块(IOC模块)
SpringMVC思想是由一个前端控制器能拦截所有请求,并智能派发;这个前端控制器是一个Servlet;应该在web.xml中配置servlet来拦截所有请求。
前端控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springMVC.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping >
然后在springMVC.xml中配置扫描组件。
配置视图解析器,能帮我们拼接页面地址,即进行地址映射。方式,通过前缀和后缀的方式进行映射。
1 2 3 4 5 6 7 8 9 <context:component-scan base-package ="cn.lizhi" > </context:component-scan > <bean id ="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/pages/" > </property > <property name ="suffix" value =".jsp" > </property > </bean >
SpringMVC中的HelloWorld的运行流程:
运行流程:
客户端点击链接发送请求
来到tomcat服务器
SpringMVC的前端控制器收到所有请求
来看请求地址和@RequestMapping标配的哪个匹配,来找到到底使用哪个类的哪个方法
前端控制器找到了目标处理器类和目标方法,直接利用返回执行目标方法;
方法执行完成以后会有一个返回值;SpringMVC认为这个返回值就是要去的页面地址
拿到方法返回值以后;用视图解析器进行拼串得到完整的页面地址;
拿到页面地址,前端控制器帮我们转发到页面;
@RequestMapping:就是告诉SpringMVC,这个方法用来处理什么请求。
如果不指定配置文件位置:
/WEB-INF/springDispatcherServlet-serlvet.xml
如果不指定也会默认去找一个文件;/WEB-INF/xxx-serlvet.xml,其中xxx是指定的前端控制器的名称,因此也可以创建这么一个xml文件作为SpringMVC的配置文件,直接放在web下。
3.1 前端控制器路径问题 SpringMVC中关于前端控制器路径配置的问题:
在整个Tomcat服务器中,服务器大web.xml中有一个DefaultServlet是url-pattern=/,我们自定义配置中的前端控制器也设置的url-pattern=/,如果访问静态资源,就会来到DispatcherServlet(前端控制器)看那个方法的RequestMapping是这个index.html。
在Tomcat中的DefaultServlet是Tomcat中处理静态资源的。除过Servlet和jsp都是静态资源;我们的前端控制设置了/禁用了tomcat服务器中的DefaultServlet。
为什么jsp又能访问;因为我们没有覆盖服务器中的JspServlet的配置。
关于上面这一块可以看下Tomcat总的web.xml文件,里面配置了jsp的servlet,静态资源的servlet,动态资源servlet,它们都设定了各种路径,来映射到这些对应个的servlet上进行处理。但是,一旦我们的DispatcherServlet进行了配置,会优先交给它进行拦截请求,到Controller中进行处理,其实本质上DispatcherServlet也是servlet,只是它将所有拦截到的请求都映射到给它自己来进行请求,交给Controller进行处理。
所以/*直接就是拦截所有请求;我们写/;也是为了迎合后面的Rest风格的URL地址。
3.2 字符编码 在web.xml中配置字符过滤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <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 > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
GET的请求编码,设置在服务器端,在server.xml的8080处添加URIEncoding=”UTF-8”
字符编码Filter一定要在其它Filter之前。
1 2 3 4 5 6 7 8 9 10 11 12 13 protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String encoding = this .getEncoding(); if (encoding != null ) { if (this .isForceRequestEncoding() || request.getCharacterEncoding() == null ) { request.setCharacterEncoding(encoding); } if (this .isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); }
3.3 SpringMVC数据传递 思考:SpringMVC除过在方法行传入原生的request和session外还能怎么样在数据带给页面?
可以在方法处传入Map、或者Model或者ModelMap。给这些参数里面保存的所有数据都会放在域中。可以在页面获取。
方式1:
1 2 3 4 5 @RequestMapping ("/handle01" )public String handle01 (Map<String, Object> map) { map.put("msg" , "你好" ); return "success" ; }
这样前端,可以通过在request域中获取到这个map中存储的值。
方式2/3:采用Model和ModelMap
1 2 3 4 5 6 7 8 9 10 11 @RequestMapping ("/handle02" )public String handle02 (Model model) { model.addAttribute("msg" , "你好model" ); return "success" ; } @RequestMapping ("/handle03" )public String handle02 (ModelMap model) { model.addAttribute("msg" , "你好modelMap" ); return "success" ; }
同方式一一样,都可以通过在前端中的request域中获取到值。
通过三种的类型打印:
1 class org .springframework .validation .support .BindingAwareModelMap
都是同一种类型。
所以,Map、Model,ModelMap,最终都是BindingAwareModelMap工作。相当于给BindingAwareModel中保存的东西都会被放在请求域中。
通过源码分析,他们之间的关系:
方法的返回值可以变为ModelAndView类型:
1 2 3 4 5 6 7 8 @RequestMapping ("/handle04" )public ModelAndView handle04 () { ModelAndView mv = new ModelAndView("success" ); mv.addObject("msg" , "您好" ); return mv; }
这种方式,同时将view和model数据进行返回;而且数据是放在请求域中。可以为页面携带数据。
SpringMVC提供了一种可以临时给Session域中保存数据的方式;使用注解:@SessionAttributes。只能使用在类上。例如:@SessionAttributes(value = {"msg"},types={String.class});给BindingAwareModelMap中保存的数据,或者ModelAndView中的数据。同时给session中放一份。value指定保存数据时要给session中方的数据的key。分别以指定value和types两种方式进行保存session域。
3.4 ModelAttribute 1 2 3 4 @RequestMapping ("/handle05" )public void handle05 (Account account) { System.out.println(account); }
在全字段更新中,首先根据Id从数据库中查询出Account对象,再根据前端的传过来的字段值进行相应的覆盖,而不是创建一个新的对象,对其赋值,否则里面空值就会覆盖原来的数据库中的值。
就是通过ModelAttribute达到这个效果。
思想核心:
SpringMVC要封装请求参数的Book对象不应该是自己new出来的。而应该是从数据库 中拿到的准备好的对象。
再来使用这个对象封装请求参数。
@ModelAttribute,可以标记在方法和对象上。
标记在方法上:
这个方法就会提前于目标方法先运行,即提前在数据中查询对应的对象信息。
将这个对象信息保存起来(方便下一个方法还能使用),保存的方式,可以通过map进行保存(保存在request域中)
可以告诉SpringMVC要封装的请求参数不应该是自己new出来的,而是从数据库中查询出来的。再使用这个对象封装参数
在接收请求参数的对象地方再标记上@ModelAttribute,其中的value就是前面保存在map中指定的Key,目的是做映射,这样就能在请求参数封装的对象中,取出从数据库中查询到的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RequestMapping ("/handle05" )public void handle05 (@ModelAttribute("account" ) Account account) { System.out.println(account); } @ModelAttribute public void modelAttribute (Map<String, Object> map) { System.out.println("ModelAttribute...测试" ); Account account = new Account(); account.setMoney(100f ); account.setAccountId(10 ); account.setAccountName("123" ); Address address = new Address(); address.setCityName("beijing" ); address.setProvinceName("beijing" ); account.setAddress(address); map.put("account" , account); }
会在每个controller执行之前,先执行ModelAttribute目标方法,然后绑定在对应的参数上,这个参数并不是新new出来的,而是map中保存的。
3.4.1 原理 这里ModelAttribute中存放的map和Model,都是同一个对象。
3.5 SpringMVC源码解析 3.5.1 前端控制器架构 —— DispatcherServlet 当请求到来的时候,其执行流程:
再进一步细看doDispatch:
ha.handle执行目标方法,即处理(控制)器的方法被调用。
processDispatchResult
总流程:
所有请求过来DispatcherServlet收到请求;
调用doDispatch()方法进行处理
检查是否是文件上传请求
通过getHandler(processedResult)根据当前请求地址找到哪个类可以进行处理,即找到处理这个请求的目标处理器,就是找到对应的Controller
根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
如果没有找到对应的处理器,就抛出异常。
通过getHandlerAdapter(),根据当前处理器你类获取到能执行这个处理器方法的适配器。就是确定当前类下哪个方法能够处理这个请求。即拿到能执行这个类的所有方法的适配器(反射工具)。(这里是注解方式的适配器)
根据当前处理器类,找到当前类的HandlerAdapter(适配器),即具体的方法。
使用适配器执行目标方法,将目标方法执行完成后的返回值作为视图名,并设置到modelAndView中。目标方法无论怎么写,最终适配器执行完成以后都会执行后的信息封装成ModelAndView
如果没有视图名设置一个默认的视图名
根据ModelAndView的信息转发到具体的页面。processDispatchResult()方法;转发到目标页面,根据方法最终执行完成后封装到ModelAndView;转发到对应页面,而且ModelAndView中的数据可以从请求域中获取。
3.5.2 getHandler()细节 怎么根据当前请求就能找到哪个类来处理。进一步进行验证,进入该方法进行一探究竟。
该方法会返回目标处理器类的执行链;
HandlerMapping:处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息。
DefaultAnnotationHandlerMapping:下面的handlerMap保存了每个请求能够通过哪个controller进行处理。通过遍历,找到请求对应的处理器。(在IOC容器一启动,就创建controller对象,再进行扫描,每个处理器都能进行处理什么请求,并保存到handlerMap属性中;下一次请求过来,就来看哪个HandlerMapping中有这个请求)
3.5.3 getHandlerAdapter 根据前面得到的处理器,找到其对应请求的适配器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ``` 存在三种方式的适配器,这里是采用注解版本的适配器。 寻求目标处理器类的适配器目的:要拿适配器才去执行目标方法。AnnotationMethodHandlerAdapter:能解析注解方法的适配器。处理器类中只要有标了注解的这些方法就可以使用。 #### 3.5.4 DispatcherServlet的属性 DispatcherServlet中的几个引用类型的属性,就是SpringMVC的九大组件。SpringMVC在工作的时候,就是这九大组件完成的 - 文件上传解析器 - 区域信息解析器 和国际化相关 - 主题解析器;强大的主题效果更换 - Handler映射信息 - Handler的适配器 - SpringMVC强大的异常解析功能;异常解析器 - viewNameTranslator - FlashMap+Manager:SpringMVC中运行重定向携带数据的功能(重定向时,也能携带数据的作用) - 视图解析器 - 共同点:都是接口,提供规范;提供了规范,进行扩展。 IOC容器启动,就会触发initStrategies方法。(onFresh()下的初始化方法) 以HandlerMapping的初始化为例: ```java
组件的初始化:去容器中找这个组件,如果没有找到就用默认的配置;(有些组件在容器是使用类型找的,有些组件是使用id找的)
3.5.5 ha.handle(…)深化 难点是方法执行。该方法是如何通过反射确定程序传入的参数,进行的方法执行?
以下列该方法为例:
1 2 3 4 5 6 7 8 9 10 11 @RequestMapping ("/handle05" )@ResponseBody public Account handle05 (@ModelAttribute("account" ) Account account, @RequestParam (value = "Tom" ) String name, Map<String,Object> map, HttpServletRequest request) { System.out.println("方法执行...." ); System.out.println(account); System.out.println(name); return account; }
handler执行,是如何通过反射能够确定上面的参数,并执行该方法的?
该方法内部,最终是通过,invokHandlerMethod(request,response,handler)执行的目标方法。其大致流程:
拿到方法的解析器
方法解析器根据当前请求地址找到真正的目标方法
创建一个方法执行器
包装原生的request,response
创建一个BindingAwareModelMap,创建一个隐含模型
执行目标方法 —— Object result = methodInvoker.invokeHandlerMethod(...);真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行modelAttribute等所有的操作都是在方法中;
找到所有@ModelAttribute注解标注的方法
args;确定modelAttribute方法执行时要使用的每一个参数的值,当前返回值的这个方法。
将目标方法参数通过暴力反射,做成可访问的。
attributeMethodToInvoke执行该目标方法。
如果方法上标注的ModelAttribute注解如果有value值,就是attrName的值。如果没设置,其值就会变为返回值类型首字母小写,比如void,或者account等。@ModelAttribute标在方法上的另一个作用;可以把方法运行后的返回值按照方法上@ModelAttribute("value")指定key放到隐含模型中,如果没有设置,就用返回值首字母小写。
把提前运行的ModelAttribute方法的返回值也放在隐含模型中。
对@ModelAttribute方法执行完以后,再次解析目标方法参数是哪些值。
最后在return处,执行目标方法
总结:
运行流程简单版
确定方法每个参数的值
标了注解:保存注解的信息;最终得到这个注解应该对应解析的值;
没标注解
看是否原生API
看是否Model或者是Map,xxx
都不是,看是否是简单类型;paramName=””
给attrName赋值;attrName(参数标了@ModelAttribute("")就是指定的,没标就是””)
确定自定义类型参数:
attrName使用参数的类型首字母小写;或者使用之前@ModelAttribute("")的值
先看隐含模型中有这个attrName作为key对应的值;如果有就从隐含模型中获取并赋值
看是否@SessionAttributes(value="xxx");标注的属性,如果是从session中拿;
否者,通过反射创建类型参数对应的对象
拿到之前创建好的对象,使用数据绑定器(WebDataBinder)将请求中的每个数据绑定到对象。
@ModelAttribute标注的方法会提前运行并把方法的运行结果放在隐含模型中;
放的时候会使用一个key;
如果@ModelAttribute("value")指定了,就用指定的value;
如果没有指定,就用返回值类型的首字母小写作为Key;
@SessionAttributes(value="xxx")最好不要使用
如果用的话,隐含模型中存在需要的值,这样就不会跳转到这一步
如果隐含模型中不存在,那就需要session域中存在需要的值,否者会报错。
3.5.6 视图和视图解析器 上一小节中,能够让模型进行了数据处理,那该如何对视图进行渲染呢。
视图解析器中的拼串,是从当前web项目下的,/WEB-INF/..进行拼接,资源请求。
如果采用转发:
1 2 3 4 @RequestMapping ("/handle06" )public String handle06 () { return "forward:/index.jsp" ; }
采用转发,是从当前项目开始资源请求(\web项目的root目录下,不加就是相对路径),而不是/WEB-INF/..。
采用这种方式,可以将请求转发给另外一个controller进行请求处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping ("/handle05" )@ResponseBody public Account handle05 (@ModelAttribute("account" ) Account account, @RequestParam (name= "name" ,defaultValue = "tom" ) String name, Map<String,Object> map, HttpServletRequest request) { System.out.println("方法执行...." ); System.out.println(account); System.out.println(name); return account; } @RequestMapping ("/handle06" )public String handle06 () { return "forward:/handle05" ; }
foward:前缀的转发,不会由我们配置的视图解析器进行解析。
如果采用重定向:
redirect:重定向的路径
原生的Servlet重定向需要加上项目名才能成功。
1 response.sendRedirect("demoName/hello.jsp" )
而使用SpringMVC会为路径自动的拼接上项目名(写法同转发)。
总结:有前缀的转发和重定向操作,配置的视图解析器就不会进行拼串。
3.5.7 视图解析源码解析
方法执行后的返回值会作为页面地址参考,转发或重定向到页面
视图解析器会进行页面地址的拼串
任何方法的返回值,都会包装成ModelAndView
核心方法processDispatchResult(...)进行页面的渲染,就是将域中的互数据在页面进行展示。下面对该方法的分析:
调用render(…)进行渲染页面。
得到View与ViewResolver;
ViewResovler的作用是根据视图名(方法的返回值)得到View对象,具体体现在它的resolverViewName(...)方法上
再进行探究,如何通过这个方法的返回值(视图名)得到View对象:
首先遍历所有的viewResolvers,调用resolverViewName(...)视图解析器根据方法的返回值,得到一个View对象。即:所有配置的视图解析器都来尝试根据视图名(返回值)得到View(视图)对象;如果能得到就返回,得不到就换下一个视图解析器。
resolverViewName(...)的具体实现createView(...)
是否重定向
如果是转发
如果没有前缀,就使用父类默认创建一个View
返回View对象
调用View对象的render方法;
最终方法落地在renderMergeOutputModel(...)方法。
期间方法中exposeModelAsRequestAttributes(...)方法将隐藏模型中的数据设置到request中的请求域中。
结论:视图解析器只是为了得到视图对象;视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面。视图对象才真正渲染视图。
1 <mvc:view-controller path ="/handle" view-name ="login" />
配置在mvc下的该标签,进行view时,经过mvc处理(不重要)。但是,只有当前映射的好用,其它的不好使。所以看下面这个高级功能:
1 <mvc:annotation-driver />
3.5.8 自定义视图和视图解析器 自定义视图解析器工作的整体流程:
让我们的视图解析器工作
得到我们的视图对象
我们的视图对象自定义渲染逻辑 - render负责渲染
1 response.getWriter().write(".." )
自定义视图和视图解析器的步骤
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class MyViewResolver implements ViewResolver , Ordered { private int order = 0 ; @Override public View resolveViewName (String viewName, Locale locale) throws Exception { if (viewName.startsWith("chemlez:" )) { return new MyView(); } return null ; } @Override public int getOrder () { return order; } public void setOrder (int order) { this .order = order; } } public class MyView implements View { @Override public String getContentType () { return "text/html" ; } @Override public void render (Map<String, ?> map, HttpServletRequest request, HttpServletResponse response) throws Exception { request.setCharacterEncoding("utf-8" ); System.out.println(map); response.setContentType("text/html" ); response.getWriter().println("自定义视图解析生效了..." ); } }
视图解析器装配:
1 2 3 <bean id ="myResolver" class ="cn.lizhi.view.MyViewResolver" > <property name ="order" value ="0" /> </bean >
3.5.9 数据转换 SpringMVC封装自定义类型对象的时候,是如何封装并绑定请求参数的?
JavaBean要和页面提交的数据进行一一绑定的过程。
牵扯到以下操作:
数据绑定期间的数据类型转换(例如:前端传递过来的Key=value都是字符串类型,就需要对其进行类型转换)
数据绑定期间的数据格式化问题(例如:日期格式转化)
数据校验,即我们提交的数据必须是合法的。
核心方法:
1 bindRequestParameters(...)
WebDataBinder:数据绑定器负责数据类型转化和数据校验
ConversionService组件:负责数据类型的转换以及格式化功能
Validators:负责数据校验工作
bindingResult:负责保存以及解析数据绑定期间数据校验产生的错误
自定义类型转换器:
不同类型的转换和格式化用它自己的converter,ConversionService存在多个converter
ConversionService是一个接口,它里面有converter进行工作;
步骤:
实现Converter接口,写一个自定义的类型转换器;
两个泛型:
S:Source:原数据类型
T:Target:需要转换的数据类型
在convert方法中写转换的逻辑
Converter是ConversionService中的组件
将自己编写的converter放进ConversionService中
将WebDataBinder中的ConversionService设置成我们这个加了自定义类型转换器的ConversionService
配置出ConversionService,配置其对应的ConversionServiiceFactory的Bean,通过set注入配置
1 2 3 4 5 6 7 8 9 10 11 12 <mvc:annotation-driven conversion-service ="converterService" /> // 1<bean id ="converterService" class ="org.springframework.context.support.ConversionServiceFactoryBean" > <property name ="converters" > <array > <bean class ="cn.lizhi.utils.StringToDate" /> </array > </property > </bean >
3.5.10 <mvc:annotation-driven/>标签 1 2 <mvc:default-servlet-handler /> // 2
通过:
只有1时,DefaultAnnotationHandlerMapping中的handlerMap中保存了每一个资源的映射信息;
静态资源不能访问:就是handlerMap中没有保存静态资源映射的请求
只有2时,动态映射HandlerMapping对应的映射没有了DefaultAnnotationHandlerMapping没有了;使用SimpleUrlHandlerMapping替换了,他的作用就是将所有请求交给tomcat,而tomcat中,只配置了dispatcherServlet,没有其他映射的servlet,所以动态请求无法处理。
当1,2都添加时,会有RequestMappingHandlerMapping:动态资源可以访问;handlerMethods属性保存了每一个请求用哪个方法来处理。
HandlerAdapters:存在RequestMappingHandlerAdapter,原来的AnnotationMethodHandlerAdapter被换成RequestMappingHandlerAdapter。
四、SSM框架的整合 核心思想:通过Spring整合另外两个框架。
整合方式:配置文件加注解的方式。
整合的思路:
搭建整合的环境
Spring的配置搭建完成
Spring整合SpringMVC框架
Spring整合Mybatis框架
4.1 环境搭建
数据库创建
1 2 3 4 5 6 7 create database ssm; use ssm; create table account( id INTEGER PRIMARY key auto_increment, name VARCHAR(32), money DOUBLE(7,2) );
pom.xml依赖导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > cn.lizhi</groupId > <artifactId > SpringMVC_03</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > war</packaging > <name > SpringMVC_03 Maven Webapp</name > <url > http://www.example.com</url > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.source > 1.8</maven.compiler.source > <maven.compiler.target > 1.8</maven.compiler.target > <spring.version > 5.0.2.RELEASE</spring.version > <slf4j.version > 1.6.6</slf4j.version > <log4j.version > 1.2.12</log4j.version > <mysql.version > 5.1.6</mysql.version > <mybatis.version > 3.4.5</mybatis.version > </properties > <dependencies > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.6.8</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aop</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > compile</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql.version}</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > <scope > provided</scope > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.0</version > <scope > provided</scope > </dependency > <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > ${log4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > ${mybatis.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 1.3.0</version > </dependency > <dependency > <groupId > c3p0</groupId > <artifactId > c3p0</artifactId > <version > 0.9.1.2</version > <type > jar</type > <scope > compile</scope > </dependency > </dependencies > <build > <finalName > SpringMVC_03</finalName > <pluginManagement > <plugins > <plugin > <artifactId > maven-clean-plugin</artifactId > <version > 3.1.0</version > </plugin > <plugin > <artifactId > maven-resources-plugin</artifactId > <version > 3.0.2</version > </plugin > <plugin > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.0</version > </plugin > <plugin > <artifactId > maven-surefire-plugin</artifactId > <version > 2.22.1</version > </plugin > <plugin > <artifactId > maven-war-plugin</artifactId > <version > 3.2.2</version > </plugin > <plugin > <artifactId > maven-install-plugin</artifactId > <version > 2.5.2</version > </plugin > <plugin > <artifactId > maven-deploy-plugin</artifactId > <version > 2.8.2</version > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.2</version > <configuration > <source > 1.8</source > <target > 1.8</target > <encoding > UTF-8</encoding > <showWarnings > true</showWarnings > </configuration > </plugin > </plugins > </pluginManagement > </build > </project >
实体类编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Double getMoney () { return money; } public void setMoney (Double money) { this .money = money; } @Override public String toString () { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}' ; } }
dao接口编写
由于我们是使用Mybatis框架,所以不需要编写其实现类,只需要写接口即可。
1 2 3 4 5 6 public interface AccountDao { public void saveAccount (Account account) ; public List<Account> findAll () ; }
编写Service接口和实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public interface AccountService { public void saveAccount (Account account) ; public List<Account> findAll () ; } public class AccountServiceImpl implements AccountService { private AccountDao accountDao; @Override public void saveAccount (Account account) { System.out.println("对用户进行保存..." ); accountDao.saveAccount(account); } @Override public List<Account> findAll () { System.out.println("业务层:查询所有用户" ); List<Account> accounts = accountDao.findAll(); return accounts; } }
4.2 Spring框架代码的编写 4.2.1 搭建和测试Spring的开发环境
在项目中创建applicationContext.xml的配置文件,编写具体的配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?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:aop ="http://www.springframework.org/schema/aop" xmlns:tx ="http://www.springframework.org/schema/tx" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <context:component-scan base-package ="cn.lizhi" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > </beans >
编写测试方法,进行测试
1 2 3 4 5 6 7 @Test public void testSpring () { ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml" ); AccountService accountService = ac.getBean("accountService" , AccountService.class ) ; accountService.findAll(); }
4.3 Spring整合SpringMVC框架
在web.xml中配置DispatcherServlet前端控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet </servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping >
在web.xml中配置DispatcherServlet过滤器解决中文乱码
1 2 3 4 5 6 7 8 9 10 11 12 13 <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 > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
创建SpringMVC.xml 的配置文件,编写配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:mvc ="http://www.springframework.org/schema/mvc" xmlns:context ="http://www.springframework.org/schema/context" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="cn.lizhi" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <bean id ="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/pages/" /> <property name ="suffix" value =".jsp" /> </bean > <mvc:resources location ="/css/" mapping ="/css/**" /> <mvc:resources location ="/images/" mapping ="/images/**" /> <mvc:resources location ="/js/" mapping ="/js/**" /> <mvc:annotation-driven /> </beans >
测试SpringMVC的框架搭建是否成功
编写index.jsp和list.jsp前端页面
1 2 3 4 <a href ="/account/findAll" > 查询所有</a > <h3 > 查询所有</h3 >
编写控制器方法
1 2 3 4 5 6 7 8 9 @Controller ("accountController" )@RequestMapping ("/account" )public class AccountController { @RequestMapping ("/findAll" ) public String findAll () { System.out.println("表面层:查询所有用户..." ); return "list" ; } }
结果:查询所有 。
Spring整合SpringMVC框架
目的:在Controller层中能成功调用service对象中的方法。
如果想在服务器启动的时候,获取到Spring的容器,那么就需要在项目启动的时候就去加载applicationContext.xml的配置文件。在web.xml中配置ContextLoaderListener监听器(该监听器只能加载WEB-INF目录下的applicationContext.xml的配置文件)。
监听器的作用:监听器的作用是监听一些事件的发生从而进行一些操作,比如监听ServletContext,HttpSession的创建,销毁,从而执行一些初始化加载配置文件的操作,当Web容器启动后,Spring的监听器会启动监听,监听是否创建ServletContext的对象,如果发生了创建ServletContext对象这个事件(当web容器启动后一定会生成一个ServletContext对象,所以监听事件一定会发生),ContextLoaderListener类会实例化并且执行初始化方法,将Spring的配置文件中配置的bean注册到Spring容器中,监听的操作是读取WEB-INF/applicationContext.xml,但是我们可以在web.xml中配置多个需要读取的配置文件,如下方所示,读取完成后所有的配置文件中的bean都会注册到spring容器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <context-param > <param-name > contextConfigLocation</param-name > <param-value > /WEB-INF/config/application-context.xml /WEB-INF/config/cache-context.xml /WEB-INF/config/captcha-context.xml /WEB-INF/config/jeecms/jeecore-context.xml /WEB-INF/config/jeecms/jeecms-context.xml /WEB-INF/config/shiro-context.xml /WEB-INF/config/plug/**/*-context.xml /WEB-INF/config/quartz-task.xml /WEB-INF/config/zxw/zxw-context.xml </param-value > </context-param >
web.xml中对监听器的配置:
1 2 3 4 5 6 7 8 9 <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.xml</param-value > </context-param >
在Controller中注入service对象,调用service对象的方法进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Controller ("accountController" )@RequestMapping ("/account" )public class AccountController { @Autowired private AccountService accountService; @RequestMapping ("/findAll" ) public String findAll () { List<Account> accounts = accountService.findAll(); System.out.println("表现层:查询所有用户..." ); return "list" ; } }
输出结果:
业务层:查询所有用户 表现层:查询所有用户…
4.4 Spring整合Mybatis框架 4.4.1 搭建和测试MyBatis的环境
在web项目中编写SqlMapConfig.xml的配置文件,编写核心配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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 > <environments default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql:///ssm?useUnicode=true& characterEncoding=utf8" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <package name ="cn.itcast.dao" /> </mappers > </configuration >
在AccountDao接口的方法上添加注解,编写SQL语句
1 2 3 4 5 6 7 8 public interface AccountDao { @Insert("insert into account (name,money) values(#{name},#{money})") public void saveAccount(Account account); @Select("select * from account") public List<Account > findAll(); }
编写测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Test public void saveAccount () throws IOException { Account account = new Account(); account.setName("小黑" ); account.setMoney(234 d); InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); AccountDao accountDao = session.getMapper(AccountDao.class ) ; accountDao.saveAccount(account); session.commit(); session.close(); is.close(); }
4.4.2 Spring整合MyBatis框架 目的:把SqlMapConfig.xml配置文件中的内容配置到applicationContext.xml配置文件中。由Spring为我们进行对象的管理。从上面的测试文件中,可以看出我们需要将工厂对象,session对象代理对象交由Spring容器进行管理。即:把Mybatis配置文件(SqlMapConfig.xml)中内容配置到spring配置文件中。
注意:
当我们使用的是代理dao的模式,dao具体实现类由Mybatis使用代理方式创建,此时Mybatis配置文件不能删除。
整合Spring和Mybatis时,Mybatis创建的Mapper.xml文件名必须和dao接口文件名一致。
配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql:///ssm?useUnicode=true& characterEncoding=utf8" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="mapperScanner" class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="cn.itcast.dao" /> </bean >
可以删除SqlSessionMap配置文件。
给dao接口加上注解@Repository
在service中注入dao对象,进行测试。
配置Spring框架声明式事务管理
配置事务管理器
1 2 3 4 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" > </property > </bean >
配置事务通知
1 2 3 4 5 6 7 <tx:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="*" propagation ="REQUIRED" read-only ="false" /> <tx:method name ="find*" propagation ="SUPPORTS" read-only ="true" /> </tx:attributes > </tx:advice >
配置AOP增强
1 2 3 4 5 6 7 <aop:config > <aop:pointcut expression ="execution(* cn.lizhi.service.impl.*.*(..))" id ="pt1" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="pt1" /> </aop:config >
五、附常用配置文件 5.1 web.xml配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app > <display-name > Archetype Created Web Application</display-name > <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <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 > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.xml</param-value > </context-param > <filter > <filter-name > HiddenHttpMethodFilter</filter-name > <filter-class > org.springframework.web.filter.HiddenHttpMethodFilter</filter-class > </filter > <filter-mapping > <filter-name > HiddenHttpMethodFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter > <filter-name > HttpPutFormContentFilter</filter-name > <filter-class > org.springframework.web.filter.HttpPutFormContentFilter</filter-class > </filter > <filter-mapping > <filter-name > HttpPutFormContentFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > </web-app >
5.2 pom.xml配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > cn.lizhi</groupId > <artifactId > SpringMVC_03</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > war</packaging > <name > SpringMVC_03 Maven Webapp</name > <url > http://www.example.com</url > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.source > 1.8</maven.compiler.source > <maven.compiler.target > 1.8</maven.compiler.target > <spring.version > 5.0.2.RELEASE</spring.version > <slf4j.version > 1.6.6</slf4j.version > <log4j.version > 1.2.12</log4j.version > <mysql.version > 5.1.6</mysql.version > <mybatis.version > 3.4.5</mybatis.version > </properties > <dependencies > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.6.8</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aop</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > compile</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql.version}</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > javax.servlet-api</artifactId > <version > 3.0.1</version > <scope > provided</scope > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.0</version > <scope > provided</scope > </dependency > <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > ${log4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > ${mybatis.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 1.3.0</version > </dependency > <dependency > <groupId > c3p0</groupId > <artifactId > c3p0</artifactId > <version > 0.9.1.2</version > <type > jar</type > <scope > compile</scope > </dependency > <dependency > <groupId > com.github.pagehelper</groupId > <artifactId > pagehelper</artifactId > <version > 5.0.0</version > </dependency > <dependency > <groupId > org.mybatis.generator</groupId > <artifactId > mybatis-generator-core</artifactId > <version > 1.3.5</version > </dependency > <dependency > <groupId > org.hibernate</groupId > <artifactId > hibernate-validator</artifactId > <version > 5.4.1.Final</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.9.0</version > </dependency > <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-annotations</artifactId > <version > 2.9.0</version > </dependency > </dependencies > <build > <finalName > ssm_crud</finalName > <pluginManagement > <plugins > <plugin > <artifactId > maven-clean-plugin</artifactId > <version > 3.1.0</version > </plugin > <plugin > <artifactId > maven-resources-plugin</artifactId > <version > 3.0.2</version > </plugin > <plugin > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.0</version > </plugin > <plugin > <artifactId > maven-surefire-plugin</artifactId > <version > 2.22.1</version > </plugin > <plugin > <artifactId > maven-war-plugin</artifactId > <version > 3.2.2</version > </plugin > <plugin > <artifactId > maven-install-plugin</artifactId > <version > 2.5.2</version > </plugin > <plugin > <artifactId > maven-deploy-plugin</artifactId > <version > 2.8.2</version > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.2</version > <configuration > <source > 1.8</source > <target > 1.8</target > <encoding > UTF-8</encoding > <showWarnings > true</showWarnings > </configuration > </plugin > </plugins > </pluginManagement > </build > </project >
5.3 SpringMVC配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd" > <context:component-scan base-package ="cn.lizhi" use-default-filters ="false" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/views/" > </property > <property name ="suffix" value =".jsp" > </property > </bean > <mvc:default-servlet-handler /> <mvc:annotation-driven /> </beans >
5.4 Spring配置文件 – applicationContext.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 <?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:aop ="http://www.springframework.org/schema/aop" xmlns:tx ="http://www.springframework.org/schema/tx" xsi:schemaLocation ="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd" > <context:component-scan base-package ="cn.lizhi" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <context:property-placeholder location ="classpath:dbconfig.properties" /> <bean id ="pooledDataSource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="jdbcUrl" value ="${jdbc.jdbcUrl}" > </property > <property name ="driverClass" value ="${jdbc.driverClass}" > </property > <property name ="user" value ="${jdbc.user}" > </property > <property name ="password" value ="${jdbc.password}" > </property > </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="configLocation" value ="classpath:mybatis-config.xml" > </property > <property name ="dataSource" ref ="pooledDataSource" > </property > <property name ="mapperLocations" value ="classpath:mapper/*.xml" > </property > </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="cn.lizhi.dao" > </property > </bean > <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg name ="sqlSessionFactory" ref ="sqlSessionFactory" > </constructor-arg > <constructor-arg name ="executorType" value ="BATCH" > </constructor-arg > </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="pooledDataSource" > </property > </bean > <aop:config > <aop:pointcut expression ="execution(* cn.lizhi.service..*(..))" id ="txPoint" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="txPoint" /> </aop:config > <tx:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="*" /> <tx:method name ="get*" read-only ="true" /> </tx:attributes > </tx:advice > </beans >
5.5 Mybatis全局配置文件 – mybatis-config.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="mapUnderscoreToCamelCase" value ="true" /> </settings > <typeAliases > <package name ="cn.lizhi.bean" /> </typeAliases > <plugins > <plugin interceptor ="com.github.pagehelper.PageInterceptor" > <property name ="reasonable" value ="true" /> </plugin > </plugins > </configuration >
5.6 Mybatis逆向工程的配置文件 – mbg.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration > <context id ="DB2Tables" targetRuntime ="MyBatis3" > <commentGenerator > <property name ="suppressAllComments" value ="true" /> </commentGenerator > <jdbcConnection driverClass ="com.mysql.jdbc.Driver" connectionURL ="jdbc:mysql://url:3306/ssm?useUnicode=true& characterEncoding=utf8" userId ="username" password ="password" > </jdbcConnection > <javaTypeResolver > <property name ="forceBigDecimals" value ="false" /> </javaTypeResolver > <javaModelGenerator targetPackage ="cn.lizhi.bean" targetProject =".\src\main\java" > <property name ="enableSubPackages" value ="true" /> <property name ="trimStrings" value ="true" /> </javaModelGenerator > <sqlMapGenerator targetPackage ="mapper" targetProject ="./src/main/resources" > <property name ="enableSubPackages" value ="true" /> </sqlMapGenerator > <javaClientGenerator type ="XMLMAPPER" targetPackage ="cn.lizhi.dao" targetProject ="./src/main/java" > <property name ="enableSubPackages" value ="true" /> </javaClientGenerator > <table tableName ="tbl_emp" domainObjectName ="Employee" > </table > <table tableName ="tbl_dept" domainObjectName ="Department" > </table > </context > </generatorConfiguration >
5.7 日志配置文件 – log4j.properties 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # Set root category priority to INFO and its only appender to CONSOLE. # log4j.rootCategory=INFO, CONSOLE debug info warn error fatal log4j.rootCategory=info, CONSOLE, LOGFILE # Set the enterprise logger category to FATAL and its only appender to CONSOLE. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=axis.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
5.8 数据库连接池 – dbconfig.properties 1 2 3 4 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://url:3306/ssm?useUnicode=true&characterEncoding=utf8 jdbc.user=username jdbc.password=password