JAVA学习笔记—SpringMVC基本使用和SSM框架整合

文章目录


一、SpringMVC基本应用

1. SpringMVC简介

1.1 MVC模式

MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想。
* M(model)模型:处理业务逻辑,封装实体
* V(view) 视图:展示内容
* C(controller)控制器:负责调度分发(1.接收请求、2.调用模型、3.转发到视图)

1.2 SpringMVC概述

SpringMVC 是一种基于 Java 的实现 MVC 设计模式的轻量级 Web 框架,属于SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。

1.3 SpringMVC快速入门

需求
客户端发起请求,服务器接收请求,执行逻辑并进行视图跳转。
步骤分析

1. 创建web项目,导入SpringMVC相关坐标
2. 配置SpringMVC前端控制器 DispathcerServlet
3. 编写Controller类和视图页面
4. 使用注解配置Controller类中业务方法的映射地址
5. 配置SpringMVC核心文件 spring-mvc.xml

1)创建web项目,导入SpringMVC相关坐标

<!-- 设置为web工程 -->
<packaging>war</packaging>
<dependencies>
<!--springMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>

2)配置SpringMVC前端控制器DispathcerServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servletclass>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

3)编写Controller类和视图页面
UserController.java

public class UserController {
    public String quick() {
    System.out.println("quick running.....");
    return "/WEB-INF/pages/success.jsp";
    }
}

/WEB-INF/pages/ success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>请求成功!</h3>
</body>
</html>

4)使用注解配置Controller类中业务方法的映射地址

@Controller
public class UserController {
@RequestMapping("/quick")
public String quick() {
System.out.println("quick running.....");
return "/WEB-INF/pages/success.jsp";
}
}

5)配置SpringMVC核心文件spring-mvc.xml

<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="com.lagou.controller"/>
</beans>

1.4 web工程执行流程

image-20210202203622636

2. SpringMVC组件概述

2.1 SpringMVC的执行流程

image-20210202203712414

1. 用户发送请求至前端控制器DispatcherServlet。
2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4. DispatcherServlet调用HandlerAdapter处理器适配器。
5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6. Controller执行完成返回ModelAndView。
7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9. ViewReslover解析后返回具体View。
10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11. DispatcherServlet将渲染后的视图响应响应用户。

2.2 SpringMVC组件解析

1. 前端控制器:DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
2. 处理器映射器:HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3. 处理器适配器:HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4. 处理器:Handler【**开发者编写**】
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到Handler。由Handler 对具体的用户请求进行处理。
5. 视图解析器:ViewResolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
6. 视图:View 【**开发者编写**】
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
***笔试题:springmvc中的三大组件是什么?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/contex
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/b
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.x
<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
<!--处理器映射器和处理器适配器功能增强-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--视图解析器-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>

2.3 SpringMVC注解解析

@Controller
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用:

<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>

@RequestMapping

* 作用:
用于建立请求 URL 和处理请求方法之间的对应关系
* 位置:
1.类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它出现的目的是为了使我们的URL可以按照模块化管理:
用户模块
/user/add
/user/update
/user/delete
...
账户模块
/account/add
/account/update
/account/delete
2.方法上:请求URL的第二级访问目录,和一级目录组成一个完整的 URL 路径。
* 属性:
1.value:用于指定请求的URL。它和path属性的作用是一样的
2.method:用来限定请求的方式
3.params:用来限定请求参数的条件
例如:params={"accountName"} 表示请求参数中必须有accountName
pramss={"money!100"} 表示请求参数中money不能是100

3. SpringMVC的请求

3.1 请求参数类型介绍

客户端请求参数的格式是: name=value&name=value……
服务器要获取请求的参数的时候要进行类型转换,有时还需要进行数据的封装
SpringMVC可以接收如下类型的参数:
基本类型参数
对象类型参数
数组类型参数
集合类型参数

3.2 获取基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。并且能自动做类型转换;自动的类型转换是指从String向其他类型的转换。

<a href="${pageContext.request.contextPath}/user/simpleParam?id=1&username=杰克">
基本类型
</a>
@RequestMapping("/simpleParam")
public String simpleParam(Integer id,String username) {
System.out.println(id);
System.out.println(username);
return "success";
}

3.3 获取对象类型参数

Controller中的业务方法参数的POJO属性名与请求参数的name一致,参数值会自动映射匹配。

<form action="${pageContext.request.contextPath}/user/pojoParam" method="post">
编号:<input type="text" name="id"> <br>
用户名:<input type="text" name="username"> <br>
<input type="submit" value="对象类型">
</form>
public class User {
Integer id;
String username;
// setter getter...
}
@RequestMapping("/pojoParam")
public String pojoParam(User user) {
System.out.println(user);
return "success";
}

3.4 中文乱码过滤器

当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。

<!--配置全局过滤的filter-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filterclass>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>

3.5 获取数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

<form action="${pageContext.request.contextPath}/user/arrayParam">
编号:<br>
<input type="checkbox" name="ids" value="1">1<br>
<input type="checkbox" name="ids" value="2">2<br>
<input type="checkbox" name="ids" value="3">3<br>
<input type="checkbox" name="ids" value="4">4<br>
<input type="checkbox" name="ids" value="5">5<br>
<input type="submit" value="数组类型">
</form>
@RequestMapping("/arrayParam")
public String arrayParam(Integer[] ids) {
System.out.println(Arrays.toString(ids));
return "success";
}

3.6 获取集合(复杂)类型参数

获得集合参数时,要将集合参数包装到一个POJO中才可以。

<form action="${pageContext.request.contextPath}/user/queryParam" method="post">
搜索关键字:
<input type="text" name="keyword"> <br>
user对象:
<input type="text" name="user.id" placeholder="编号">
<input type="text" name="user.username" placeholder="姓名"><br>
list集合<br>
第一个元素:
<input type="text" name="userList[0].id" placeholder="编号">
<input type="text" name="userList[0].username" placeholder="姓名"><br>
第二个元素:
<input type="text" name="userList[1].id" placeholder="编号">
<input type="text" name="userList[1].username" placeholder="姓名"><br>
map集合<br>
第一个元素:
<input type="text" name="userMap['u1'].id" placeholder="编号">
<input type="text" name="userMap['u1'].username" placeholder="姓名"><br>
第二个元素:
<input type="text" name="userMap['u2'].id" placeholder="编号">
<input type="text" name="userMap['u2'].username" placeholder="姓名"><br>
<input type="submit" value="复杂类型">
</form>
public class QueryVo {
private String keyword;
private User user;
private List<User> userList;
private Map<String, User> userMap;
}
@RequestMapping("/queryParam")
public String queryParam(QueryVo queryVo) {
System.out.println(queryVo);
return "success";
}

3.7 自定义类型转换器

SpringMVC 默认已经提供了一些常用的类型转换器;例如:客户端提交的字符串转换成int型进行参数设置,日期格式类型要求为:yyyy/MM/dd 不然的话会报错,对于特有的行为,SpringMVC提供了自定义类型转换器方便开发者自定义处理。

<form action="${pageContext.request.contextPath}/user/converterParam">
生日:<input type="text" name="birthday">
<input type="submit" value="自定义类型转换器">
</form>
public class DateConverter implements Converter<String, Date> {
    public Date convert(String dateStr) {
        //将日期字符串转换成日期对象 返回
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
        date = format.parse(dateStr);
        } catch (ParseException e) {
        e.printStackTrace();
        } 
        return date;
    }
}
<!--处理器映射器和适配器增强-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotationdriven>
<!--自定义转换器配置-->
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.lagou.converter.DateConverter"></bean>
</set>
</property>
</bean>
@RequestMapping("/converterParam")
public String converterParam(Date birthday) {
System.out.println(birthday);
return "success";
}

3.8 相关注解

@RequestParam
当请求的参数name名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定

<a href="${pageContext.request.contextPath}/user/findByPage?pageNo=2">
分页查询
</a>
/*
@RequestParam() 注解
defaultValue 设置参数默认值
name 匹配页面传递参数的名称
required 设置是否必须传递参数,默认值为true;如果设置了默认值,值自动改为false
*/
@RequestMapping("/findByPage")
public String findByPage(@RequestParam(name = "pageNo", defaultValue = "1")
Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize) {
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}

@RequestHeader
获取请求头的数据。

@RequestMapping("/requestHead")
public String requestHead(@RequestHeader("cookie") String cookie) {
System.out.println(cookie);
return "success";
}

@CookieValue
获取cookie中的数据。

@RequestMapping("/cookieValue")
public String cookieValue(@CookieValue("JSESSIONID") String jesessionId) {
System.out.println(jesessionId);
return "success";
}

3.9 获取Servlet相关API

SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

@RequestMapping("/servletAPI")
public String servletAPI(HttpServletRequest request, HttpServletResponse
response, HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}

4. SpringMVC的响应

4.1 SpringMVC响应方式介绍

页面跳转
\1. 返回字符串逻辑视图
\2. void原始ServletAPI
\3. ModelAndView
返回数据
\1. 直接返回字符串数据
\2. 将对象或集合转为json返回(任务二演示)

4.2 返回字符串逻辑视图

直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转到指定页面

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

4.3 void原始ServletAPI

我们可以通过request、response对象实现响应

@RequestMapping("/returnVoid")
public void returnVoid(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 1.通过response直接响应数据
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("拉勾网");
----------------------------------------
request.setAttribute("username", "拉勾教育");
// 2.通过request实现转发
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,
response);
----------------------------------------
// 3.通过response实现重定向
response.sendRedirect(request.getContextPath() + "/index.jsp");
}

4.4 转发和重定向

企业开发我们一般使用返回字符串逻辑视图实现页面的跳转,这种方式其实就是请求转发。
我们也可以写成:forward转发
如果用了forward:则路径必须写成实际视图url,不能写逻辑视图。它相当于:

request.getRequestDispatcher("url").forward(request,response)

使用请求转发,既可以转发到jsp,也可以转发到其他的控制器方法。

@RequestMapping("/forward")
public String forward(Model model) {
model.addAttribute("username", "拉勾招聘");
return "forward:/WEB-INF/pages/success.jsp";
}

Redirect重定向
我们可以不写虚拟目录,springMVC框架会自动拼接,并且将Model中的数据拼接到url地址上

@RequestMapping("/redirect")
public String redirect(Model model) {
model.addAttribute("username", "拉勾教育");
return "redirect:/index.jsp";
}

4.5 ModelAndView

4.5.1 方式一

在Controller中方法创建并返回ModelAndView对象,并且设置视图名称

@RequestMapping("/returnModelAndView1")
public ModelAndView returnModelAndView1() {
/*
Model:模型 作用封装数据
View:视图 作用展示数据
*/
ModelAndView modelAndView = new ModelAndView();
//设置模型数据
modelAndView.addObject("username", " lagou");
//设置视图名称
modelAndView.setViewName("success");
return modelAndView;
}
4.5.2 方式二

在Controller中方法形参上直接声明ModelAndView,无需在方法中自己创建,在方法中直接使用该对象设置视图,同样可以跳转页面

@RequestMapping("/returnModelAndView2")
public ModelAndView returnModelAndView2(ModelAndView modelAndView) {
//设置模型数据
modelAndView.addObject("username", "itheima");
//设置视图名称
modelAndView.setViewName("success");
return modelAndView;
}

4.6 @SessionAttributes

如果在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes,配置需要在session中存放的数据范围,Spring MVC将存放在model中对应的数据暂存到 HttpSession 中。
注意:@SessionAttributes只能定义在类上

@Controller
@SessionAttributes("username") //向request域存入的key为username时,同步到session域中
public class UserController {
@RequestMapping("/forward")
public String forward(Model model) {
model.addAttribute("username", "子慕");
return "forward:/WEB-INF/pages/success.jsp";
}
@RequestMapping("/returnString")
public String returnString() {
return "success";
}
}

5. 静态资源访问的开启

当有静态资源需要加载时,比如jquery文件,通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表对所有的静态资源都进行处理操作,这样就不会执行Tomcat内置的DefaultServlet处理,我们可以通过以下两种方式指定放行静态资源:
方式一

<!--在springmvc配置文件中指定放行资源-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/img/**" location="/img/"/>

方式二

<!--在springmvc配置文件中开启DefaultServlet处理静态资源-->
<mvc:default-servlet-handler/>

二、springmvc进阶

1. ajax异步交互

Springmvc默认用MappingJackson2HttpMessageConverter对json数据进行转换,需要加入
jackson的包;同时使用 <mvc:annotation-driven />

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>

1.1 @RequestBody

该注解用于Controller的方法的形参声明,当使用ajax提交并指定contentType为json形式时,通过
HttpMessageConverter接口转换为对应的POJO对象。

<button id="btn1">ajax异步提交</button>
<script>
$("#btn1").click(function () {
let url = '${pageContext.request.contextPath}/ajaxRequest';
let data = '[{"id":1,"username":"张三"},{"id":2,"username":"李四"}]';
$.ajax({
type: 'POST',
url: url,
data: data,
contentType: 'application/json;charset=utf-8',
success: function (resp) {
alert(JSON.stringify(resp))
}
})
})
</script>
@RequestMapping(value = "/ajaxRequest")
public void ajaxRequest(@RequestBody List<User>list) {
System.out.println(list);
}

1.2 @ResponseBody

该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数
据如:json,xml等,通过Response响应给客户端。

/*
@RequestMapping
produces = "application/json;charset=utf-8" 响应返回数据的mime类型和编码,默认为
json
*/
@RequestMapping(value = "/ajaxRequest")
@ResponseBody
public List<User> ajaxRequest(@RequestBody List<User> list) {
System.out.println(list);
return list;
}

2. RESTful

2.1 什么是RESTful

Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
DELETE:删除(Delete)

客户端请求原来风格URL地址RESTful风格URL地址
查询所有/user/findAllGET /user
根据ID查询/user/findById?id=1GET /user/{1}
新增/user/savePOST /user
修改/user/updatePUT /user
删除/user/delete?id=1DELETE /user/{1}

2.2 代码实现

@PathVariable
用来接收RESTful风格请求地址中占位符的值
@RestController
RESTful风格多用于前后端分离项目开发,前端通过ajax与服务器进行异步交互,我们处理器通常返
回的是json数据所以使用@RestController来替代@Controller和@ResponseBody两个注解。

// @Controller
@RestController
public class RestFulController {
@GetMapping(value = "/user/{id}")
// 相当于 @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
// @ResponseBody
public String get(@PathVariable Integer id) {
return "get:" + id;
} 
@PostMapping(value = "/user")
// @ResponseBody
public String post() {
return "post";
} 
@PutMapping(value = "/user")
// @ResponseBody
public String put() {
return "put";
} 
@DeleteMapping(value = "/user/{id}")
// @ResponseBody
public String delete(@PathVariable Integer id) {
return "delete:"+ id;
}
}

3. 文件上传

3.1 文件上传三要素

表单项 type=“file”
表单的提交方式 method=“POST”
表单的enctype属性是多部分表单形式 enctype=“multipart/form-data"

3.2 文件上传原理

当form表单修改为多部分表单时,request.getParameter()将失效。
当form表单的enctype取值为 application/x-www-form-urlencoded 时,
form表单的正文内容格式是: name=value&name=value
当form表单的enctype取值为 mutilpart/form-data 时,请求正文内容就变成多部分形式

3.3 单文件上传

1)导入fileupload和io坐标

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

2)配置文件上传解析器

<!--文件上传解析器-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定文件上传的最大值为5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
<!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 -->
<property name="maxInMemorySize" value="40960"></property>
</bean>

3)编写文件上传代码

<form action="${pageContext.request.contextPath}/fileUpload" method="post"
enctype="multipart/form-data">
名称:<input type="text" name="username"> <br>
文件:<input type="file" name="filePic"> <br>
<input type="submit" value="单文件上传">
</form>
@RequestMapping("/fileUpload")
public String fileUpload(String username, MultipartFile filePic) throws
IOException {
System.out.println(username);
// 获取文件名
String originalFilename = filePic.getOriginalFilename();
//保存文件
filePic.transferTo(new File("d:/upload/"+originalFilename));
return "success";
}

3.4 多文件上传

<form action="${pageContext.request.contextPath}/filesUpload" method="post"
enctype="multipart/form-data">
名称:<input type="text" name="username"> <br>
文件1:<input type="file" name="filePic"> <br>
文件2:<input type="file" name="filePic"> <br>
<input type="submit" value="多文件上传">
</form>
@RequestMapping("/filesUpload")
public String filesUpload(String username, MultipartFile[] filePic) throws
IOException {
System.out.println(username);
for (MultipartFile multipartFile : filePic) {
// 获取文件名
String originalFilename = multipartFile.getOriginalFilename();
// 保存到服务器
multipartFile.transferTo(new File("d:/upload/" + originalFilename));
} 
    return "success";
}

4. 异常处理

4.1 异常处理的思路

在Java中,对于异常的处理一般有两种方式:
一种是当前方法捕获处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合。
另一种是自己不处理,而是抛给调用者处理(throws),调用者再抛给它的调用者,也就是一直向上抛。
在这种方法的基础上,衍生出了SpringMVC的异常处理机制。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

image-20210202211406822

4.2 自定义异常处理器

步骤分析

1. 创建异常处理器类实现HandlerExceptionResolver
2. 配置异常处理器
3. 编写异常页面
4. 测试异常跳转

1)创建异常处理器类实现HandlerExceptionResolver

public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("error", ex.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}

2)配置异常处理器

@Component
public class GlobalExecptionResovler implements HandlerExceptionResolver {}
<bean id="globalExecptionResovler"
class="com.lagou.exception.GlobalExecptionResovler"></bean>

3)编写异常页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>error</title>
</head>
<body>
<h3>这是一个最终异常的显示页面</h3>
<p>${error}</p>
</body>
</html>

4)测试异常跳转

@RequestMapping("/testException")
public String testException() {
int i = 1 / 0;
return "success";
}

4.3 web的处理异常机制

<!--处理500异常-->
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
<!--处理404异常-->
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>

5. 拦截器

5.1 拦截器(interceptor)的作用

Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

5.2 拦截器和过滤器区别

关于interceptor和filter的区别,如图所示:

image-20210202211644474

5.3 快速入门

1)创建拦截器类实现HandlerInterceptor接口

public class MyInterceptor1 implements HandlerInterceptor {
// 在目标方法执行之前 拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) {
System.out.println("preHendle1");
return true;
} /
/ 在目标方法执行之后,视图对象返回之前 执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) {
System.out.println("postHandle1");
} /
/ 在流程都执行完毕后 执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) {
System.out.println("afterCompletion1");
}
}

2)配置拦截器

<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.lagou.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>

3)测试拦截器的拦截效果
编写Controller,发请求到controller,跳转页面

@Controller
public class TargetController {
@RequestMapping("/target")
public String targetMethod() {
System.out.println("目标方法执行了...");
return "success";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>success...</h3>
<% System.out.println("视图执行了....");%>
</body>
</html>

5.4 拦截器链

开发中拦截器可以单独使用,也可以同时使用多个拦截器形成一条拦截器链。开发步骤和单个拦截器是一样的,只不过注册的时候注册多个,注意这里注册的顺序就代表拦截器执行的顺序。
同上,再编写一个MyHandlerInterceptor2操作,测试执行顺序:

5.5 知识小结

拦截器中的方法说明如下:

image-20210202211834276

3. SSM整合

1.1 需求和步骤分析

需求
使用ssm框架完成对 account 表的增删改查操作。
步骤分析

1. 准备数据库和表记录
2. 创建web项目
3. 编写mybatis在ssm环境中可以单独使用
4. 编写spring在ssm环境中可以单独使用
5. spring整合mybatis
6. 编写springMVC在ssm环境中可以单独使用
7. spring整合springMVC

1.2 环境搭建

1)准备数据库和表记录

CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`money` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert into `account`(`id`,`name`,`money`) values (1,'tom',1000),
(2,'jerry',1000);

2)创建web项目

1.3 编写mybatis在ssm环境中可以单独使用

需求:基于mybatis先来实现对account表的查询
1)相关坐标

<!--mybatis坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

2)Account实体

public class Account {
private Integer id;
private String name;
private Double money;
}

3)AccountDao接口

public interface AccountDao {
public List<Account> findAll();
}

4)AccountDao.xml映射

<?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.lagou.dao.AccountDao">
<select id="findAll" resultType="Account">
select * from account
</select>
</mapper>

5)mybatis核心配置文件
jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=root

SqlMapConfig.xml

<?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-->
<properties resource="jdbc.properties"/>
<!--类型别名配置-->
<typeAliases>
<package name="com.lagou.domain"/>
</typeAliases>
<!--环境配置-->
<environments default="mysql">
<!--使用MySQL环境-->
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射-->
<mappers>
<package name="com.lagou.dao"/>
</mappers>
</configuration>

6)测试代码

public class MyBatisTest {
@Test
public void testMybatis() throws Exception {
// 加载核心配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获得sqlsession工厂对象
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(is);
// 获得sqlsession会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获得mapper代理对象
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
// 执行
List<Account> list = accountDao.findAll();
for (Account account : list) {
System.out.println(account);
} /
/ 释放资源
sqlSession.close();
}
}

1.4 编写spring在ssm环境中可以单独使用

1)相关坐标

<!--spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>

2)AccountService接口

public interface AccountService {
public List<Account> findAll();
}

3)AccountServiceImpl实现

@Service
public class AccountServiceImpl implements AccountService {
@Override
public List<Account> findAll() {
System.out.println("findAll执行了....");
return null;
}
}

4)spring核心配置文件
applicationContext.xml

<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注解组件扫描-->
<context:component-scan base-package="com.lagou.service"/>
</beans>

5)测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
@Autowired
private AccountService accountService;
@Test
public void testSpring() throws Exception {
List<Account> list = accountService.findAll();
System.out.println(list);
}
}

1.5 spring整合mybatis

1)整合思想
将mybatis接口代理对象的创建权交给spring管理,我们就可以把dao的代理对象注入到service中,
此时也就完成了spring与mybatis的整合了。
2)导入整合包

<!--mybatis整合spring坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>

3)spring配置文件管理mybatis
注意:此时可以将mybatis主配置文件删除。

<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注解组件扫描-->
    <context:component-scan base-package="com.lagou.service"/>
<!--spring整合mybatis-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<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>
<!--SqlSessionFactory创建交给spring的IOC容器-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据库环境配置-->
<property name="dataSource" ref="dataSource"/>
<!--类型别名配置-->
<property name="typeAliasesPackage" value="com.lagou.domain"/>
<!--如果要引入mybatis主配置文件,可以通过如下配置-->
<!--<property name="configLocation"
value="classpath:SqlMapConfig.xml"/>-->
</bean>
<!--映射接口扫描配置,由spring创建代理对象,交给IOC容器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lagou.dao"/>
</bean>
</beans>

4)修改AccountServiceImpl

@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
}

1.6 编写springMVC在ssm环境中可以单独使用

需求:访问到controller里面的方法查询所有账户,并跳转到list.jsp页面进行列表展示
1)相关坐标

<!--springMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

2)导入页面资源

image-20210202215317092

3)前端控制器DispathcerServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servletclass>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--post中文处理-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filterclass>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>
</web-app>

4)AccountController和 list.jsp

@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/findAll")
public String findAll(Model model) {
List<Account> list = new ArrayList<>();
list.add(new Account(1,"张三",1000d));
list.add(new Account(2,"李四",1000d));
model.addAttribute("list", list);
return "list";
}
}
<c:forEach items="${list}" var="account">
<tr>
<td>
<input type="checkbox" name="ids">
</td>
<td>${account.id}</td>
<td>${account.name}</td>
<td>${account.money}</td>
<td>
<a class="btn btn-default btn-sm" href="update.jsp">修改</a>&nbsp;
<a class="btn btn-default btn-sm" href="">删除</a>
</td>
</tr>
</c:forEach>

5)springMVC核心配置文件

<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="com.lagou.controller"/>
<!--mvc注解增强-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--实现静态资源映射-->
<mvc:default-servlet-handler/>
</beans>

1.7 spring整合springMVC

1)整合思想
spring和springMVC其实根本就不用整合,本来就是一家。
但是我们需要做到spring和web容器整合,让web容器启动的时候自动加载spring配置文件,web容
器销毁的时候spring的ioc容器也销毁。
2)spring和web容器整合
ContextLoaderListener加载【掌握】
可以使用spring-web包中的ContextLoaderListener监听器,可以监听servletContext容器的创建和
销毁,来同时创建或销毁IOC容器。

<!--spring 与 web容器整合-->
<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>

3)修改AccountController

@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(Model model) {
List<Account> list = accountService.findAll();
model.addAttribute("list", list);
return "list";
}
}

1.8 spring配置声明式事务

1)spring配置文件加入声明式事务

<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解支持-->
<tx:annotation-driven/>
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
}

2)add.jsp

<form action="${pageContext.request.contextPath}/account/save" method="post">
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" class="form-control" id="name" name="name"
placeholder="请输入姓名">
</div>
<div class="form-group">
<label for="age">余额:</label>
<input type="text" class="form-control" id="age" name="age"
placeholder="请输入余额">
</div>
<div class="form-group" style="text-align: center">
<input class="btn btn-primary" type="submit" value="提交" />
<input class="btn btn-default" type="reset" value="重置" />
<input class="btn btn-default" type="button" onclick="history.go(-1)"
value="返回" />
</div>
</form>

3)AccountController

@RequestMapping("/save")
public String save(Account account){
accountService.save(account);
return "redirect:/account/findAll";
}

4)AccountService接口和实现类

public void save(Account account);
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
@Override
public void save(Account account) {
accountDao.save(account);
}
}

5)AccountDao

void save(Account account);

6)AccountDao.xml映射

<insert id="save" parameterType="Account">
insert into account (name, money) values (#{name}, #{money})
</insert>

1.9 修改操作

1.9.1 数据回显

① AccountController

@RequestMapping("/findById")
public String findById(Integer id, Model model) {
Account account = accountService.findById(id);
model.addAttribute("account", account);
return "update";
}

② AccountService接口和实现类

Account findById(Integer id);
@Override
public Account findById(Integer id) {
return accountDao.findById(id);
}

③ AccountDao接口和映射文件

Account findById(Integer id);
<select id="findById" parameterType="int" resultType="Account">
select * from account where id = #{id}
</select>

④ update.jsp

<form action="${pageContext.request.contextPath}/account/update" method="post">
<input type="hidden" name="id" value="${account.id}">
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" class="form-control" id="name" name="name"
value="${account.name}" placeholder="请输入姓名">
</div>
<div class="form-group">
<label for="money">余额:</label>
<input type="text" class="form-control" id="money" name="money"
value="${account.money}" placeholder="请输入余额">
</div>
<div class="form-group" style="text-align: center">
<input class="btn btn-primary" type="submit" value="提交" />
<input class="btn btn-default" type="reset" value="重置" />
<input class="btn btn-default" type="button" onclick="history.go(-1)"
value="返回" />
</div>
</form>
1.9.2 账户更新

① AccountController

@RequestMapping("/update")
public String update(Account account){
accountService.update(account);
return "redirect:/account/findAll";
}

② AccountService接口和实现类

void update(Account account);
@Override
public void update(Account account) {
accountDao.update(account);
}

③ AccountDao接口和映射文件

void update(Account account);
<update id="update" parameterType="Account">
update account set name = #{name},money = #{money} where id = #{id}
</update>

1.10 批量删除

1)list.jsp

<script>
$('#checkAll').click(function () {
$('input[name="ids"]').prop('checked', $(this).prop('checked'));
})
$('#deleteBatchBtn').click(function () {
if (confirm('您确定要删除吗?')) {
if ($('input[name="ids"]:checked').length > 0) {
$('#deleteBatchForm').submit();
} else {
alert('想啥呢?')
}
}
})
</script>

2)AccountController

@RequestMapping("/deleteBatch")
public String deleteBatch(Integer[] ids) {
accountService.deleteBatch(ids);
return "redirect:/account/findAll";
}

3)AccountService接口和实现类

void deleteBatch(Integer[] ids);
@Override
public void deleteBatch(Integer[] ids) {
accountDao.deleteBatch(ids);
}

4)AccountDao接口和映射文件

void deleteBatch(Integer[] ids);
<delete id="deleteBatch" parameterType="int">
delete from account
<where>
<foreach collection="array" open="id in(" close=")" separator=","
item="id">
#{id}
</foreach>
</where>
</delete>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值