1.SpringMVC入门

1.1 概述

SpringWebMVC是基于servlet API构建的原始Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发

1.2 快速入门

依赖管理

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>

配置中央控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--SpringMVC中央控制器-->
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

创建自定义控制器类

1
2
3
4
5
6
7
8
9
@Controller
public class UserController {

@RequestMapping("/hello")
public String hello() {
System.out.println("Hello Springmvc");
return "success";
}
}

创建Spring配置文件

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
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 开启SpringMVC注解支持 -->
<mvc:annotation-driven/>

<!-- 注解扫描器 -->
<context:component-scan base-package="com.web" />

<!-- 视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

在WEB-INF/jsp目录下创建success.jsp

启动并测试

1.3 Java Config

创建SpringMVC启动配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebConfig.class};
}

@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}

配置Spring注入Bean

1
2
3
4
5
6
7
@Configuration
@ComponentScan(basePackages = {"com.web"}, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)
})
public class RootConfig {

}

配置SpringMVC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.web.controller"})
public class WebConfig {

/**
* 视图解析器
* @return ViewResolver
*/
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);

return resolver;
}
}

1.4 SpringMVC请求流程

1
The Spring Web model-view-controller (MVC) framework is designed around a DispatcherServlet that dispatches requests to handlers, with configurable handler mappings, view resolution, locale and theme resolution as well as support for uploading files. The default handler is based on the @Controller and @RequestMapping annotations, offering a wide range of flexible handling methods.

SpringMVC内置Bean

Bean Type Explanation
HandlerMapping 根据某些条件将传入的请求映射到处理程序和前后处理程序(处理程序拦截器)列表
HandlerAdapter 帮助DispatcherServlet调用映射到请求的处理程序,而不管实际调用的是哪个处理程序
HandlerExceptionResolver 将异常映射到视图还允许更复杂的异常处理代码
ViewResolver 将基于逻辑字符串的视图名称解析为实际视图类型
LocaleResolver 解析客户端使用的区域设置,以便能够提供国际化视图
ThemeResolver 解决Web应用程序可以使用的主题,例如,提供个性化布局
MultipartResolver 分析多部分请求,例如支持处理来自HTML表单的文件上载
FlashMapManager 存储和检索“输入”和“输出”flashmap,这些flashmap可用于将属性从一个请求传递到另一个请求,通常是通过重定向传递的

2.SpringMVC常用注解

2.1 @RequestMapping

RequestMapping主要是对请求的url进行映射

参数

  • value:配置请求映射路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello")
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }
  • method:允许请求的Http方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello", method = {RequestMethod.POST, RequestMethod.GET})
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }
  • params:用于指定限制请求参数的条件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello", params = {"userName=MAX"})
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }
  • headers:用于指定限制请求头的条件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello", headers = {"Accept"})
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }
  • consumes:指定可消费媒体类型的列表来缩小主映射范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello", consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }
  • produces:指定可产生的媒体类型列表来缩小主映射范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class UserController {

    @RequestMapping(value = "/hello", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String hello() {
    System.out.println("Hello Springmvc");
    return "success";
    }
    }

2.2 @RequestParam

获取表单请求的参数

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/hello")
public String hello(@RequestParam("name") String name) {
System.out.println("Hello Springmvc");
return "success";
}
}

2.3 @RequestBody

获取Http请求体

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/hello")
public String hello(@RequestBody String requestBody) {
System.out.println("request body: " + requestBody);
return "success";
}
}

2.4 @PathVariable

获得请求url中的动态参数的

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/hello/{userName}")
public String hello(@PathVariable("userName") String userName) {
System.out.println("userName: " + userName);
return "success";
}
}

2.5 @RquestHeader

获取Http请求头

1
2
3
4
5
6
7
8
9
10
11
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/displayHeaderInfo")
public String displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) {
System.out.println("encoding: " + encoding);
System.out.println("keepAlive: " + keepAlive);
return "success";
}
}

2.6 @CookieValue

获取Http Cookie信息

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/displayHeaderInfo")
public String displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
System.out.println("cookie: " + cookie);
return "success";
}
}

2.7 @SessionAttrbutes

存储对象到Http Session中

1
2
3
4
5
6
7
8
9
10
11
@Controller
@RequestMapping("/user")
@SessionAttributes({"currentUser"})
public class UserController {

@RequestMapping("/displayHeaderInfo")
public String displayHeaderInfo(Model model) {
model.addAttribute("currentUser", "admin");
return "success";
}
}

3.请求参数绑定&自定义类型转换

3.1 请求参数绑定

不论是GET请求,还是POST请求。提交的数据都是k=v的形式

SpringMVC通过请求参数绑定,将客户端传递过来的参数自动绑定到不同的数据对象上

自动绑定支持的数据类型

  • 基本数据类型和字符串
  • 实体类型(Java Bean)
  • 集合数据类型List、Map等

3.2 字符编码过滤器

不论是发送GET请求还是POST请求,一旦涉及到中文,就会存在中文乱码的问题。在SpringMVC中,专门设计了用于进行字符串编码过滤的过滤器,在web.xml中进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Java Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}

@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new CharacterEncodingFilter("UTF-8", true)
};
}
}

3.3 自定义类型转换器

自定义转换类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StringToDateConvert implements Converter<String, Date> {

@Override
public Date convert(String s) {
if(s == null) {
throw new RuntimeException("不能为空");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
return df.parse(s);
} catch (ParseException e) {
throw new RuntimeException("数据转换错误");
}
}
}

自定义转换配置

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
<?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:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 开启SpringMVC注解支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>

<!-- 注解扫描器 -->
<context:component-scan base-package="com.web" />

<!-- 视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!-- 配置自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.web.convert.StringToDateConvert"/>
</set>
</property>
</bean>
</beans>

Java Config

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
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.web.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {

@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);

return resolver;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.jsp");
}

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToDateConvert());
}
}

3.4 自定义拦截器

在很多时候,我们需要对某些请求来处理前进行拦截,来对请求进行一些数据处理或非法性校验。SpringMVC提供了拦截器来实现这些对请求拦截的功能

自定义拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LoginInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

Object sessionUser = request.getSession().getAttribute("sessionUser");
if(sessionUser == null) {
response.sendRedirect("index.jsp");
return false;
}
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
}

拦截器配置

1
2
3
4
5
6
7
8
9
10
11
<!-- 自定义拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 进行拦截:/**表示拦截所有controller -->
<mvc:mapping path="/**" />
<!-- 不进行拦截 -->
<mvc:exclude-mapping path="/index.jsp"/>
<mvc:exclude-mapping path="/hello"/>
<bean class="com.web.interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

Java Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.web.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {

@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);

return resolver;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.jsp");
}
}

3.5 HiddenHttpMethodFilter

如果想要以Restful Api的方式发送请求,那么就需要在项目中添加HiddenHttpMethodFilter过滤器来实现

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
<!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>

<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--SpringMVC中央控制器-->
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

Java Config

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 class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}

@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new CharacterEncodingFilter("UTF-8", true),
new HiddenHttpMethodFilter()
};
}
}

测试页面

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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>restful api</title>
</head>
<body>
<center>
<p>GET请求</p>
<form action="users" method="get">
<input type="submit" value="Get请求"/>
</form>
<p>POST请求</p>
<form action="users" method="post">
<input type="submit" value="Post请求"/>
</form>
<p>PUT请求</p>
<form action="users" method="post">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="Put请求"/>
</form>
<p>Delete请求</p>
<form action="users/1001" method="post">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" value="Delete请求"/>
</form>
</center>
</body>
</html>

控制器代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RestController
public class UserController {


@GetMapping("/users")
public String list() {
return "user list";
}

@PostMapping("/users")
public String save() {
return "save user";
}

@PutMapping("/users")
public String update() {
return "update user";
}

@DeleteMapping("users/{id}")
public String delete(@PathVariable("id") int id) {
return "delete user";
}
}

4.返回值类型&响应数据类型

4.1 请求转发&重定向

请求转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/list")
public String list() {
return "forward:/user/save";
}

@RequestMapping("/save")
public String save() {
return "success";
}
}

重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/list")
public String list() {
return "redirect:/user/save";
}

@RequestMapping("/save")
public String save() {
return "success";
}
}

4.2 静态资源过滤

1
2
3
<mvc:resources location="/js/" mapping="/js/**"/> 
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>

Java Config

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
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.web.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {

@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);

return resolver;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.jsp");
}

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToDateConvert());
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
}
}

4.3 响应Json数据格式

添加依赖

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
@Controller
@RequestMapping("/user")
@SessionAttributes({"currentUser"})
public class UserController {

@ResponseBody
@RequestMapping(value="/displayHeaderInfo", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public String displayHeaderInfo(Model model) {
model.addAttribute("currentUser", "admin");
return "success";
}
}

5.文件上传下载

5.1 文件上传

添加依赖

1
2
3
4
5
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>

jsp

1
2
3
4
5
<h1>Please upload a file</h1>
<form method="post" action="user/upload" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>

controller

1
2
3
4
5
@RequestMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
System.out.println(file.getOriginalFilename());
return "success";
}

xml配置

1
2
3
4
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>

Java Config

1
2
3
4
5
6
7
@Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setMaxUploadSize(100000);

return commonsMultipartResolver;
}

5.2 文件下载

添加依赖

1
2
3
4
5
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>

controller

1
2
3
4
5
6
7
8
9
@RequestMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
String fileName = "/Users/Desktop/spring-framework-3.2.9.RELEASE-dist.zip";
HttpHeaders headers=new HttpHeaders();//设置响应头
headers.add("Content-Disposition", "attachment;filename="+fileName);
HttpStatus statusCode = HttpStatus.OK;//设置响应吗
ResponseEntity<byte[]> response=new ResponseEntity<>(IOUtils.toByteArray(new FileInputStream(fileName)), headers, statusCode);
return response;
}

6.SpringMVC整合MyBatis

6.1 整合思路

ssm框架整合思路

  1. 配置Spring框架
  2. 配置SpringMVC框架
  3. Spring集成SpringMVC
  4. 配置MyBatis
  5. 集成MyBatis

6.2 Spring配置

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
<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>4.3.18.RELEASE</spring.version>
</properties>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

实体类

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
public class User {
private int id;
private String userName;
private int age;

public User() {}

public User(int id, String userName, int age) {
this.id = id;
this.userName = userName;
this.age = age;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
'}';
}
}

Dao层

1
2
3
4
5
6
7
8
9
10
public interface UserDao {

List<User> findAll();

boolean save(User user);

boolean update(User user);

boolean deleteById(int id);
}

Dao实现层

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
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public List<User> findAll() {
List<User> users = new ArrayList<>();
users.add(new User(1001, "mike", 20));
users.add(new User(1002, "bob", 21));
users.add(new User(1003, "max", 22));

return users;
}

@Override
public boolean save(User user) {
return false;
}

@Override
public boolean update(User user) {
return false;
}

@Override
public boolean deleteById(int id) {
return false;
}
}

Service层

1
2
3
4
5
6
7
8
9
10
public interface UserService {

List<User> findAll();

boolean save(User user);

boolean update(User user);

boolean deleteById(int id);
}

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
26
@Service("userService")
public class UserServiceImpl implements UserService {

@Autowired
private UserDao userDao;

@Override
public List<User> findAll() {
return userDao.findAll();
}

@Override
public boolean save(User user) {
return userDao.save(user);
}

@Override
public boolean update(User user) {
return userDao.update(user);
}

@Override
public boolean deleteById(int id) {
return userDao.deleteById(id);
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 注册扫描 -->
<context:component-scan base-package="com.web">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>

测试类

1
2
3
4
5
6
7
8
9
10
public class UserServiceTest {

@Test
public void testUserService() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)applicationContext.getBean("userService");
List<User> list = userService.findAll();
System.out.println(list);
}
}

6.3 SpringMVC配置

添加依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

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
<!--SpringMVC字符过滤器-->
<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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--SpringMVC中央控制器-->
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

UserController

1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/list")
public String list() {
return "success";
}
}

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
25
26
27
28
29
30
31
32
33
<?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:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 注解扫描器 -->
<context:component-scan base-package="com.web">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!-- 静态资源过滤 -->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>

<!-- 视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!-- 开启SpringMVC注解支持 -->
<mvc:annotation-driven />
</beans>

6.4 Spring集成SpringMVC

web.xml

1
2
3
4
5
6
7
8
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@RequestMapping("/list")
public String list() {
List<User> list = userService.findAll();
System.out.println(list);
return "success";
}
}

6.5 配置MyBatis

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>

<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>

jdbc.properties

1
2
3
4
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm_db
username=root
password=111111

mybatis-config.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>
<properties resource="jdbc.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>

<mappers>
<mapper resource="com/web/mapper/UserMapper.xml"/>
</mappers>
</configuration>

UserMapper.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.web.dao.UserDao">
<select id="findAll" resultType="com.web.domain.User">
select * from t_user
</select>
</mapper>

测试类

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
package com.web.domain.test;

import com.web.dao.UserDao;
import com.web.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserTest {

@Test
public void testUserDao() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> list = userDao.findAll();
System.out.println(list);
}
}

6.6 集成MyBatis

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>

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
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- 注册扫描 -->
<context:component-scan base-package="com.web">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!-- 加载外部properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!-- druid数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/web/mapper/*.xml"/>
</bean>

<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.web.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

<!-- 事务管理 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 开启事务注解支持 -->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.web.dao.UserDao">
<select id="findAll" resultType="com.web.domain.User">
select * from t_user
</select>

<insert id="save" parameterType="com.web.domain.User">
insert into t_user(username, age) values(#{userName}, #{age})
</insert>
</mapper>

UserDao

1
2
3
4
5
6
7
8
9
10
11
@Repository("userDao")
public interface UserDao {

List<User> findAll();

void save(User user);

void update(User user);

void deleteById(int id);
}

UserService

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
@Transactional(readOnly = true)
@Service("userService")
public class UserServiceImpl implements UserService {

@Autowired
private UserDao userDao;

@Override
public List<User> findAll() {
return userDao.findAll();
}

@Override
@Transactional
public boolean save(User user) {
userDao.save(user);
return true;
}

@Override
public boolean update(User user) {
userDao.update(user);
return true;
}

@Override
public boolean deleteById(int id) {
userDao.deleteById(id);
return true;
}
}

7.SpringMVC测试

mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。

定义Controller类

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
@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@RequestMapping(value = "/findAll", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public List<User> findAll() {
return userService.findAll();
}

@RequestMapping("/findById/{id}")
public User findById(@PathVariable int id) {
return userService.findById(id);
}

@RequestMapping("/save")
public boolean save(User user) {
return userService.save(user);
}

@RequestMapping("/update")
public boolean update(User user) {
return userService.update(user);
}

@RequestMapping("/deleteById/{id}")
public boolean deleteById(@PathVariable int id) {
return userService.deleteById(id);
}
}

编写单元测试

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
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {RootConfig.class, WebConfig.class})
public class SpringMVCTest {

@Autowired
private WebApplicationContext wac;

private MockMvc mockMvc;

@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}

@Test
public void testHelloController() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/hello")
.accept(MediaType.TEXT_HTML_VALUE))
.andDo(MockMvcResultHandlers.print())
.andReturn();

int status = mvcResult.getResponse().getStatus();
System.out.println(mvcResult.getResponse().getContentAsString());
}

@Test
public void testFindAll() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/user/findAll")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andDo(MockMvcResultHandlers.print())
.andReturn();

System.out.println(mvcResult.getResponse().getStatus());
System.out.println(mvcResult.getResponse().getContentAsString());
}

@Test
public void testFindById() throws Exception {
mockMvc.perform(get("/user/findById/1001"))
.andDo(MockMvcResultHandlers.print());
}

@Test
public void testSave() throws Exception {
mockMvc.perform(post("/user/save")
.param("id", "1001")
.param("name", "Jack")
.param("age", "20"))
.andDo(MockMvcResultHandlers.print());
}

@Test
public void testUpdate() throws Exception {
mockMvc.perform(post("/user/update")
.param("id", "1001")
.param("name", "Jack")
.param("age", "30"))
.andDo(MockMvcResultHandlers.print());
}

@Test
public void testDeleteById() throws Exception {
mockMvc.perform(post("/user/deleteById/1001"))
.andDo(MockMvcResultHandlers.print());
}
}