38-SpringMVC-qianfeng-笔记
一、SpringMVC概述
Spring MVC是由Spring官方提供的基于MvC设计理念的web框架。
SpringMVC是基于Servlet封装的用于实现MWC控制的框架,实现前端和服务端的交互。
①:SpringMVC优势
- 严格遵守了MVC分层思想
- 采用了松耦合、插件式结构;相比较于我们封装的BaseServlet以及其他的一些MVC框架来说更灵活、更具扩展性
- SpringMVC是基于Spring的扩展、提供了一套完善的MVC注解
- SpringMVC在数据绑定、视图解析都提供了多种处理方式,可灵活配置
- SpringMVC对RESTful URL设计方法提供了良好的支持
②:SpringMVC本质工作
二、SpringMVC框架部署
①:创建Web工程
01. 创建步骤
2. 补全项目结构 |
|
02. 添加依赖
- spring-context
- spring-aspects
- spring-jdbc
- spring-web
- spring-webmvc
- spring-test
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.18version>
<scope>testscope>
dependency>
03. 创建SpringMVC配置文件
- 在resources目录下创建名为
spring-servlet.xml
的文件
- 添加MVC命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/aop
http://www.springframework.org/schema/aop/spring-aop.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:annotation-config/>
<mvc:annotation-driven />
<context:component-scan base-package="com" />
beans>
04. 在web.xml中配置SpringMVC的前控制器
SpringMVC提供了一个名为DispatcherServlet的类(SpringMVCi前端控制器),用于拦截用户请求交由
SpringMVC处理
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
三、SpringMVC框架使用
在SpringMVC中,我们把接收用户请求、处理用户请求的类称之为Controlelr(控制器)
①:创建控制器
01. 创建控制器类
- 创建一个名为
com.qfedu.controllers
的包(包需要在Spring注解扫描的范围内)
- 创建一个类(无需做任何的继承和实现)
- 在类上添加
@Controller
注解声明此类为SpringMVC的控制器
- 在类上添加
@RequestMapping("url")
声明此控制器类的请求url
@Controller
@RequestMapping("/book")
public class BookController {
}
02. 在控制器类中定义处理请求的方法
- 在一个控制器类中可以定于多个方法处理不同的请求
- 在每个方法上添加
@RequestMapping("url")
用于声明当前方法请求的url
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add")
public void add(){
System.out.println("**********Book add************");
}
@RequestMapping("/list")
public void list(){
System.out.println("**********Book list************");
}
}
03. 访问
注意:若无法访问 检查Tomcat路径是否修改 |
|
②:静态资源配置
00. 创建前端页面
<%@page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加图书title>
head>
<body>
<h3>添加图书h3>
<form action="" method="post">
<p>图书名称:<input type="text"/>p>
<p>图书作者:<input type="text"/>p>
<p>图书价格:<input type="text"/>p>
<p><input type="submit" value="提交"/>p>
form>
body>
html>
01. /* 和 /的区别
- /*拦截所有的HTTP请求,包括.jsP的请求,都做为控制器类的请求路径来处理
- /拦截所有的HTTP请求,但不包括,jsp的请求,不会放行静态资源的请求(html/css/js/图片)
1. 使用/* |
|
2. 使用/ |
|
3. 添加静态资源css样式后在访问 |
|
02. 静态资源放行配置
在springMVCl的配置文件,添加如下静态资源放行的配置
<mvc:resources mapping="/css/**" location="css/"/>
<mvc:resources mapping="/js/**" location="js/"/>
<mvc:resources mapping="/imgs/**" location="imgs/"/>
<mvc:resources mapping="/pages/**" location="pages/"/>
③:前端提交数据到控制器
01.设置表单提交路径
book-add,jsp表单的action属性设置控制器类的url和对应方法的url的组合路径 |
02.表单提交
- 表单提交:输入框需要提供name属性,SpringMVC控制器是通过name属性取值的
<body>
<h3>添加图书h3>
<form action="book/add" method="post">
<p>图书名称:<input type="text" name="bookName"/>p>
<p>图书作者:<input type="text" name="bookAuthor"/>p>
<p>图书价格:<input type="text" name="bookPrice"/>p>
<p><input type="submit" value="提交"/>p>
form>
body>
03. URL提交
04. AJAX提交
- AJAX提交:请求行、请求头、请求体都可以用来传值
<script type="text/javascript" src="js/jquery-3.6.0.min.js">script>
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript">
$("#btn1").click(function (){
var obj = {};
obj.bookName = "Java";
obj.bookAuthor = "张三";
obj.bookPrice = 9.99;
$.ajax({
url:"book/add",
type: "post",
headers:{},
contentType:"application/json",
data:obj,
success:function (res){
console.log(res)
}
});
});
script>
④:控制器接收前端提交的数据
01.请求行传值
- 表单提交
- URL提交
- $.ajax()请求的url传值
$.post()/$.get()
中的{}传值
@RequestParam
注解用于接收请求行传递的数据
前端提交数据
<form action="book/add" method="post">
<p>图书名称:<input type="text" name="bookName"/>p>
<p>图书作者:<input type="text" name="bookAuthor"/>p>
<p>图书价格:<input type="text" name="bookPrice"/>p>
<p><input type="submit" value="提交"/>p>
form>
控制器接收数据
@RequestMapping("/add")
public void add(@RequestParam("bookName") String bookName,
@RequestParam("bookAuthor") String bookAuthor,
@RequestParam("bookPrice") String bookPrice){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
}
注意:如果控制器方法中接收数据的参数名与请求行传值的key一致
则@RequestParami注解可省略 |
|
02. 请求头传值
前端代码
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$("#btn1").click(function () {
$.ajax({
url: "book/list",
type: "post",
headers: {
token: "My name is Coke"
},
success: function (res) {
console.log(res)
}
});
});
</script>)
后端代码
@RequestMapping("/list")
public void list(@RequestHeader("token") String token){
System.out.println("**********Book list************");
System.out.println(token);
}
03. 请求行和请求头同时传值
前端代码
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$("#btn1").click(function () {
$.ajax({
url: "book/add?bookName=Java&bookAuthor=Coke&bookPrice=9.9",
type: "post",
headers: {
token: "My name is Coke"
},
success: function (res) {
console.log(res)
}
});
});
</script>
后端代码
@RequestMapping("/add")
public void add(String bookName,
String bookAuthor,
String bookPrice,
@RequestHeader("token") String token){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
System.out.println("token = " + token);
}
04.请求体传值
1.方式一(request输入流读数据)
前端代码
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$("#btn1").click(function (){
var obj = {};
obj.bookName = "Java";
obj.bookAuthor = "Coke";
obj.bookPrice = 9.99;
$.ajax({
url:"book/update",
type: "post",
contentType:"application/json",
data:obj,
success:function (res){
console.log(res)
}
});
});
</script>
后端代码
@RequestMapping("/update")
public void update(HttpServletRequest request){
System.out.println("**********Book update************");
try {
ServletInputStream is = request.getInputStream();
StringBuffer buffer = new StringBuffer();
byte[] bs = new byte[100];
int len = -1;
while ((len = is.read(bs)) != -1) {
String s = new String(bs, 0, len);
buffer.append(s);
}
System.out.println("buffer.toString() = " + buffer.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
2. 方式二(使用@RequestBody)
- 添加依赖(@RequestBody需要将json格式数据转换成java对象)
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.3version>
dependency>
1. 创建Book类并提供get set 等方法 |
|
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.6.0.min.js">script>
<script type="text/javascript">
$("#btn1").click(function (){
var obj = {};
obj.bookName = "Java";
obj.bookAuthor = "Coke";
obj.bookPrice = 9.99;
var s = JSON.stringify(obj)
$.ajax({
url:"book/update",
type: "post",
contentType:"application/json",
data:s,
success:function (res){
console.log(res)
}
});
});
script>
@RequestMapping("/update")
public void update(@RequestBody Book book){
System.out.println("**********Book update************");
System.out.println(book);
}
⑤:控制器响应前端请求
01. 控制器响应同步请求
处理同步请求的方法的返回类型定义为String或者ModelAndView,以实现页面的跳转
1. 返回类型为String
1. 转发
1. 添加跳转后tips.jsp界面 |
|
@RequestMapping("/add")
public String add(String bookName, String bookAuthor, String bookPrice){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
return "/tips.jsp";
}
3. 测试 |
|
2. 重定向
@RequestMapping("/add")
public String add(String bookName, String bookAuthor, String bookPrice){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
return "redirect:/tips.jsp";
}
2.返回类型为ModelAndView
1. 转发
@RequestMapping("/add")
public ModelAndView add(String bookName, String bookAuthor, String bookPrice){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
ModelAndView modelAndView = new ModelAndView("/tips.jsp");
return modelAndView;
}
2. 重定向
@RequestMapping("/add")
public ModelAndView add(String bookName, String bookAuthor, String bookPrice){
System.out.println("**********Book add************");
System.out.println("bookName = " + bookName);
System.out.println("bookAuthor = " + bookAuthor);
System.out.println("bookPrice = " + bookPrice);
ModelAndView modelAndView = new ModelAndView("redirect:/tips.jsp");
return modelAndView;
}
02. 控制器响应异步请求
异步请求:ajax请求
1. 使用response中的输出流进行响应
- 控制器方法的返回类型为void
- 控制器方法添加HttpServletResponse response参数
- 在方法中通过response获取输出流,使用流响应ajax清求
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.6.0.min.js">script>
<script type="text/javascript">
$("#btn1").click(function (){
var obj = {};
obj.bookName = "Java";
obj.bookAuthor = "Coke";
obj.bookPrice = 9.99;
var s = JSON.stringify(obj)
$.ajax({
url:"book/update",
type: "post",
contentType:"application/json",
data:s,
success:function (res){
console.log(res)
}
});
});
script>
@RequestMapping("/update")
public void update(@RequestBody Book book, HttpServletResponse response) throws IOException {
System.out.println("**********Book update************");
String s = new ObjectMapper().writeValueAsString(book);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println(s);
out.flush();
out.close();
}
3. 测试 |
|
2.直接在控制器方法返回响应的对象
- 控制器方法的返回类型设置为响应给ajax请求的对象类型
- 在控制器方法前添加
@ResponseBody
注解,将返回的对象转换成JSON响应给ajax请求
@RequestMapping("/update")
@ResponseBody
public List<Book> update() {
System.out.println("**********Book update************");
ArrayList<Book> books = new ArrayList<>();
books.add(new Book(1,"Java","Coke",9.9));
books.add(new Book(2,"Linux","KangKang",9.99));
return books;
}
⑥:控制器响应同步请求的数据传递
对于同步请求的转发响应,我们可以传递参数到转发的页面
01. 返回类型为String
1. 前端代码 |
|
@RequestMapping("/add")
public String add(String bookName, String bookAuthor, Double bookPrice, Model model){
model.addAttribute("key","value");
model.addAttribute("book",new Book(1,"Java","Coke",9.9));
return "/tips.jsp";
}
@RequestMapping("/add")
public String add(String bookName, String bookAuthor, Double bookPrice, HttpServletRequest request){
request.setAttribute("key","value");
request.setAttribute("book",new Book(1,"Java","Coke",9.9));
return "/tips.jsp";
}
3. 测试 |
|
02. 返回类型ModelAndView
@RequestMapping("/add")
public ModelAndView add(String bookName, String bookAuthor, Double bookPrice){
ModelAndView model = new ModelAndView("/tips.jsp");
model.addObject("key","value");
model.addObject("book",new Book(1,"Java","Coke",9.9));
return model;
}
⑦:中文乱码问题
01. 前端编码
<%@page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<meta charset="UTF-8">
02.设置服务器编码设置
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
tomcat/conf/server.xml |
|
03. 后端(SpringMVC)编码设置
<filter>
<filter-name>EncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
<init-param>
<param-name>forceEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>EncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
04. 测试
中文乱码已解决 |
|
四、SpringMVC的请求处理流程
①:请求处理流程
SpringMVC通过前端控制器(DispatcherServlet)拦截并处理用户请求的
②:SpringMVC的核心组件
DispatcherServlet
前端控制器、总控制器
HandlerMapping
处理器映射(可配置)
- 作用:负责根据用户请求的URL找到对应的Handler(Controller)
Handler Adapter
处理器适配器
- 作用:按照处理器映射器解析的用户请求的调用链,通过适配器模式完成Handler的调用
Handler
处理器/控制器
ModelAndView
视图模型
- 作用:用于封装处理器返回的数据以及相应的视图
- ModelAndView = Model + View
ViewResolver
视图解析器(可配置)
View
视图
③:处理器映射器
不同的处理器映射器对UL处理的方式也不相同,使用对应的处理器映射器之后我们的前端请求规则也需要发生相应的变化
SpringMVC提供的处理器映射器:
BeanNameUrlHandlerMapping
根据控制器的ID访问控制器
SimpleUrlHandlerMapping
根据控制器配置的URL访问(默认)
配置处理器映射器:
- 在
SpringMVC
的配置文件中通过bean标签声明处理器映射器
- 配置
BeanNameUrlHandlerMapping
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
- 配置
SimpleUrlHandlerMapping
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/aaa">bookControllerprop>
props>
property>
bean>
④:视图解析器
Spring提供了多个视图解析器
- UrlBasedViewResolver
- InternalResourceViewResolver
- UrlBasedViewResolver需要依赖jstl
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
- 配置视图解析器
UrlBasedViewResolver
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="com.fasterxml.jackson.annotation.JsonView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
- 配置视图解析器
InternalResourceViewResolver
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
测试 |
|
五、日期格式处理
①:使用对象来接收数据
1. 创建一个新的类 |
|
2. 修改访问路径 |
|
3. 测试(注意:实体类的属性名要和前端输入框的name属性名称一样) |
|
②:日期格式处理
如果前端需要输入日期数据,在控制器中转换成Date对象,SpringMVC要求前端输入的日期格式必须为
yyyy/MM/dd
如果甲方要求日期格式必须为指定的格式,而这个指定格式SpringMVC不接受,该如何处理呢?
01. 自定义日期转换器
1. 添加一个日期属性Data(提供构造器及get set等方法) |
|
2.添加输入框 |
|
public class MyDataConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = null;
try {
date = format.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
02. 配置自定义日期转换器
<mvc:annotation-driven conversion-service="converterFactory"/>
<bean id="converterFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.it.utils.MyDataConverter"/>
set>
property>
bean>
测试 |
|
六、文件上传
①:SpringMvc框架部署
步骤 略~
- 添加SpringMVC所需的依赖
- Spring:context aspects jdbc test web webmvc jackson
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.3version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
- 创建SpringMVC配置文件
- 在web.Xml中配置SpringMVC的前端控制器
<servlet>
<servlet-name>springMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-servlet.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<context:component-scan base-package="com.it"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/imgs/**" location="/imgs/"/>
②:案例准备
01. 创建index.jsp(首页面)
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<body>
<table width="100%" height="700">
<tr>
<td width="200" style="border-right: lightblue 2px solid; background: rgba(255,0,0,0.1)">
<ul>
<li><a href="book-add.jsp" target="mainFrame">添加图书a> li>
<li><a href="">图书列表a>li>
ul>
td>
<td>
<iframe name="mainFrame" width="100%" height="700" frameborder="0">iframe>
td>
tr>
<tr>tr>
table>
body>
html>
02. 创建book-add.jsp(图书添加页面)
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<body>
<h4>添加图书信息h4>
<form action="">
<p>图书名称:<input type="text" name="">p>
<p>图书作者:<input type="text" name="">p>
<p>图书价格:<input type="text" name="">p>
<p>图书封面:<input type="file" name="">p>
<p><input type="submit" value="提交">p>
form>
body>
html>
03.创建tips.jsp页面
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<body>
body>
html>
04.设置index.jsp为默认页面
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
05. 创建BookConverter类
@Controller
@RequestMapping("/book")
public class BookConverter {
@RequestMapping("/add")
public String addBook(){
System.out.println("*************Book add***************");
return "/tips.jsp";
}
}
③:文件上传实现
01.创建实体类
public class Book {
private int bookId;
private String bookName;
private String bookAuthor;
private double bookPrice;
private String bookImg;
}
02. 前端提交文件
- 表单提交方式必须为post
- 表单entype属性设置为multipart/form-data
<body>
<h4>添加图书信息h4>
<form action="book/add" method="post" enctype="multipart/form-data">
<p>图书名称:<input type="text" name="bookName">p>
<p>图书作者:<input type="text" name="bookAuthor">p>
<p>图书价格:<input type="text" name="bookPrice">p>
<p>图书封面:<input type="file" name="imgFile">p>
<p><input type="submit" value="提交">p>
form>
body>
03.控制器接收数据和文件
SpringMVC处理上传文件需要借助于CommonsMultipartResolver文件解析器
- 添加依赖 commons-io commons-fileupload
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.11.0version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.3version>
dependency>
- 在spring-servlet.xml中配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
<property name="maxInMemorySize" value="102400"/>
<property name="defaultEncoding" value="utf-8"/>
bean>
- 空制器接收文件
- 在处理文件上传的方法中定义一个MultiPartFile类型的对象,就可以接受图片了
04.保存数据(图片)
@Controller
@RequestMapping("/book")
public class BookConverter {
@RequestMapping("/add")
public String addBook(Book book, MultipartFile imgFile, HttpServletRequest request) throws IOException {
System.out.println("*************Book add***************");
String originalFilename = imgFile.getOriginalFilename();
String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
String filename = System.currentTimeMillis() + ext;
String dir = request.getServletContext().getRealPath("imgs");
String savePath = dir + "/" + filename;
imgFile.transferTo(new File(savePath));
book.setBookImg("imgs/" + filename);
return "/tips.jsp";
}
}
1. 在imgs路径下放一个文件,否则空文件不会被加载 |
|
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<body>
图书名称:${book.bookName}
<hr>
图书作者:${book.bookAuthor}
<hr>
图书价格:${book.bookPrice}
<hr>
图书封面:${book.bookImg}
<hr>
body>
html>
3. 测试 |
|
七、 文件下载
①:显示文件列表
1.在BookConverter类中添加查询方法 (查询图片列表) |
@RequestMapping("list")
@ResponseBody
public String[] listImgs(HttpServletRequest request){
String path = request.getServletContext().getRealPath("imgs");
File imgDir = new File(path);
String[] fileName = imgDir.list();
return fileName;
}
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<head>
<title>图书列表title>
head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous">script>
<body>
<h4>图书列表h4>
<script type="text/javascript" src="js/jquery-3.6.0.min.js">script>
<script type="text/javascript">
$.get("book/list",function(res) {
for (let i = 0; i < res.length; i++) {
var fn = res[i];
var htmlStr = ""
$("#container").append(htmlStr);
}
},"json")
script>
<div class="row" id="container">
div>
body>
html>
3. 修改index.jsp代码 |
|
4. 测试 |
|
②:文件下载实现
1. BookConverter中添加一个下载方法 |
@RequestMapping("download")
public void downloadImg(String fname, HttpServletRequest request, HttpServletResponse response) throws Exception {
String path = request.getServletContext().getRealPath("imgs");
String filePath = path + "/" +fname;
FileInputStream inputStream = new FileInputStream(filePath);
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("application/exe");
response.addHeader("Content-Disposition","attachment;filename="+fname);
IOUtils.copy(inputStream,outputStream);
}
2. 在list.jap中添加下载URL |
|
八、统一异常处理
在我们的应用系统运行的过程中,可能由于运行环境、用户操作、资源不足等各方面的原因导致系统出现异常(HTTP状态异常、Exception);如果系统出现了异常,这些异常将会通过浏览器呈现给用户,而这种异常的显示是设有必要,因此我们可以在服务器进行特定的处理一当系统出现异常之后,呈现给用户一个统一的、可读的的异常提示页面。
①:HTTP异常状态统一处理
HTTP Status 404
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" language="java" %>
<html>
<head>
head>
<body>
您的访问地址有误,请检查....
body>
html>
<error-page>
<error-code>404error-code>
<location>/404.jsplocation>
error-page>
测试:(访问一个不存在的地址) |
|
②:Java代码异常的统一处理
01. 基于Servlet
- 创建异常提示页面:err.jsp
- 在web.xml中进行配置
<error-page>
<exception-type>java.lang.NumberFormatExceptionexception-type>
<location>/err.jsplocation>
error-page>
02. SpringMVC处理
public class MyExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public String nullHandler(){
return "/err1.jsp";
}
@ExceptionHandler(NumberFormatException.class)
public String formatHandler(){
return "/err2.jsp";
}
}
2. 针对不同的异常展示不同的jsp页面 |
|
九、拦截器
①:拦截器介绍
SpringMVC提供的拦截器就类似于Servlet–api中的过滤器,可以对控制器的请求进行拦截实现相关的预处理和后处理。
- 过滤器
- 是Servlet规范的一部分,所有的web项目都可以使用
- 过滤器在web.xml配置(可以使用注解),能够拦截所有web清求
- 拦截器
- 是SpringMVC框架的实现,只有在SpringMVC框架中才能使用
- 拦截器在SpringMVC配置文件进行配置,不会拦截SpringMVC放行的资源(jsp\html\css.…)
②:自定义拦截器
01.创建拦截器
public class MyInterceptor1 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("***********预处理***********");
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
if ("bookName".equals(name)){
return true;
}
}
response.setStatus(400);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("***********后处理***********");
modelAndView.addObject("tips","这是通过拦截器的后处理添加的数据");
}
}
02. 配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/book/query"/>
<mvc:mapping path="/book/add"/>
<mvc:mapping path="/student/**"/>
<mvc:exclude-mapping path="/student/add"/>
<bean class="com.it.utils.MyInterceptor1"/>
mvc:interceptor>
mvc:interceptors>
03.添加控制器方法
@RequestMapping("query")
public String query(String bookName){
System.out.println(bookName);
Book book = new Book();
book.setBookName(bookName);
return "/tips.jsp";
}
③:拦截器链
将多个拦截器按照一定的顺序构成一个执行链
十、SSM整合
①:创建Web项目
01. 创建web工程
(完成maven工程web项目结构)步骤略
02. 添加web项目依赖
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
03.配置Tomcat运行环境
②:部署MyBatis
01. 添加MyBatis依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
<scope>providedscope>
dependency>
02. 创建mybatis-config.xml
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
configuration>
③:部署Spring、SpringMVC
01.添加依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.18version>
<scope>testscope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.3version>
dependency>
02.创建Spring配置(多个文件分开配置)
spring-context.xml
只配置注解声明、以及类的管理
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.it"/>
beans>
spring-mvc.xml
进行mvc相关的配置,例如静态资源配置、拦截器配置等
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
beans>
spring-mybatis.xml
进行Spring-与MyBatis整合相关的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
beans>
④:配置SpringMvc前端控制器
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-*.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
⑤:整合配置(IOC)
01.导入mybatis-spring依赖
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
02.配置druid连接池
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
druid.driver=com.mysql.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/db_mybatis_demo2?characterEncoding=utf-8
druid.username=root
druid.password=root
## 连接池参数
druid.pool.init=1
druid.pool.minIdle=3
druid.pool.maxActive=20
druid.pool.timeout=30000
<context:property-placeholder location="classpath:druid.properties"/>
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${druid.driver}"/>
<property name="url" value="${druid.url}"/>
<property name="username" value="${druid.username}"/>
<property name="password" value="${druid.password}"/>
<property name="initialSize" value="${druid.pool.init}"/>
<property name="minIdle" value="${druid.pool.minIdle}"/>
<property name="maxActive" value="${druid.pool.maxActive}"/>
<property name="maxWait" value="${druid.pool.timeout}"/>
bean>
03.配置SqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"/>
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
<property name="typeAliasesPackage" value="com.it.beans"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
bean>
04.配置MapperScannerConfigurer
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.it.dao"/>
bean>
⑥:整合配置(AOP)
使用Spring提供的事务管理完成DAO操作的事务管理
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
⑦:整合测试
01.完成User的查询操作
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private int userId;
private String userName;
private String userPwd;
private String realName;
private String userImg;
}
public interface UserDAO {
User queryUserByName(String userName);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.it.dao.UserDAO">
<resultMap id="UserMap" type="User">
<id column="user_id" property="userId"/>
<result column="user_name" property="userName"/>
<result column="user_pwd" property="userPwd"/>
<result column="user_realname" property="realName"/>
<result column="user_img" property="userImg"/>
resultMap>
<select id="queryUserByName" resultMap="UserMap">
select user_id,user_name,user_pwd,user_realname,user_img
from users
where user_name= #{userName}
select>
mapper>
02. 对DAO单元测试
- 添加junit、spring-test(前面已经导入过)依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-context.xml",
"classpath:spring-mvc.xml",
"classpath:spring-mybatis.xml"})
public class UserDAOTest {
@Autowired
private UserDAO userDAO;
@Test
public void queryUserByName() {
User user = userDAO.queryUserByName("李四");
System.out.println(user);
}
}
03.对Service单元测试
public interface UserService {
User checkLogin(String username, String password);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
@Transactional
public User checkLogin(String username, String password) {
User user = userDAO.queryUserByName("李四");
if (user != null & user.getUserPwd().equals(password)){
return user;
}
return null;
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-context.xml",
"classpath:spring-mvc.xml",
"classpath:spring-mybatis.xml"})
public class UserServiceTest {
@Resource
private UserService userService;
@Test
public void checkLogin() {
User user = userService.checkLogin("李四", "123123");
System.out.println(user);
}
}
⑧:整合Controller
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/login")
public String login(String username, String password, HttpServletRequest request){
User user = userService.checkLogin(username, password);
if (user == null){
request.setAttribute("tips","用户名或密码错误!");
return "/login.jsp";
}else {
request.getSession().setAttribute("user",user);
return "/index.jsp";
}
}
}
<%@page contentType="text/html;charset=utf-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<h3>这是主页面~h3>
<h4>Hello ${user.userName}~~h4>
body>
html>
<%@page contentType="text/html;charset=utf-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Titletitle>
head>
<body>
<h3>登录页面h3>
${tips}
<form action="user/login" method="post">
<p>账号:<input type="text" name="username">p>
<p>密码:<input type="password" name="password">p>
<p><input type="submit" value="登录">p>
form>
body>
html>
4. 测试 |
|
十一 纯注解开发(补)
①:使用注解开发(入门案例)
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("add")
@ResponseBody
public String addUser(String username){
System.out.println("*******User add*******"+username);
return "{'module':'username'}";
}
}
3. 创建springmvc的配置类,加载controller对应的bean |
@Configuration
@ComponentScan("com.it.controller")
public class SpringMvcConfig {
}
4. 4. 定义一个serlvet容器启动的配置类,在里面加载spring的配置 |
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMvcConfig.class);
return context;
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
5. 测试 |
|
②:bean加载控制
1. 设定扫描范围为精确范围 |
|
2. 排除掉controller包内的bean |
|
|
3. 不区分Spring与SpringMVC的环境,加载到同一个环境中 |
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMvcConfig.class);
return context;
}
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringConfig.class);
return context;
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
4. 不区分Spring与SpringMVC的环境,加载到同一个环境中 (简化版) |
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
③:PostMan工具
官网:[https://www.postman.com/](https://www.postman.com/) |
|
④:postman发送get和post请求
1. get请求 |
|
2. post请求 |
|
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
return new Filter[] {filter};
}
⑤post发送json数据
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.3version>
dependency>
2. 在springmvc配置文件中添加@EnableWebMvc |
|
01. 集合参数(Json)
@RequestMapping("list")
@ResponseBody
public String listParamForJson(@RequestBody List<String> lists){
System.out.println("lists = " + lists);
return lists.toString();
}
02. pojo参数(Json)
@RequestMapping("users")
@ResponseBody
public String pojoParamForJson(@RequestBody User users){
System.out.println("users = " + users);
return "users = " + users;
}
03. pojo集合参数
@RequestMapping("listUser")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> users){
System.out.println("users = " + users);
return "users = " + users;
}
04. 日期参数
@RequestMapping("date")
@ResponseBody
public String dateParam(Date date,
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date2,
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3){
System.out.println("date = " + date);
System.out.println("date2 = " + date2);
System.out.println("date3 = " + date3);
return date+","+date2+","+date3;
}
⑤:REST风格
01. 入门案例
1. 在BookController类中添加增删改查方法 |
@Controller
public class BookController {
@RequestMapping(value = "books", method = RequestMethod.POST)
@ResponseBody
public String add(){
System.out.println("Book add *****");
return "Book add *****";
}
@RequestMapping(value ="books/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("Book delete *****" + id);
return "Book delete *****" + id;
}
@RequestMapping(value ="books", method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody Book book){
System.out.println("Book update *****" + book);
return "Book update *****" + book;
}
@RequestMapping(value ="books/{id}", method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("Book getById *****" + id);
return "Book getById *****" + id;
}
}
02.RESTful快速开发
@RestController
@RequestMapping("books")
public class BookController2 {
@PostMapping
public String add(){
System.out.println("Book add *****");
return "Book add *****";
}
@DeleteMapping("{id}")
public String delete(@PathVariable Integer id){
System.out.println("Book delete *****" + id);
return "Book delete *****" + id;
}
@PutMapping
public String update(@RequestBody Book book){
System.out.println("Book update *****" + book);
return "Book update *****" + book;
}
@GetMapping("{id}")
public String getById(@PathVariable Integer id){
System.out.println("Book getById *****" + id);
return "Book getById *****" + id;
}
}
⑥:基于RESTful页面数据交互
01.数据准备
1. 创建实体类 |
|
2. 创建config配置文件 |
|
@Controller
@ComponentScan("com.it.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
return new Filter[]{filter};
}
}
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book){
System.out.println("*******Book save*******" + book);
return "*******Book save*******" + book;
}
@GetMapping
public List<Book> getAll(){
ArrayList<Book> bookList = new ArrayList<>();
Book book1 = new Book();
book1.setType("计算机");
book1.setName("Java核心");
book1.setDescription("从入门到精通~");
bookList.add(book1);
Book book2 = new Book();
book2.setType("计算机");
book2.setName("Linux核心");
book2.setDescription("从入门到精通~");
bookList.add(book2);
return bookList;
}
}
3. 测试 |
|
02. 放行静态资源
1 |
|
2. 创建SpringMvcSupport类 |
|
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**","/pages/");
registry.addResourceHandler("/js/**","/js/");
registry.addResourceHandler("/css/**","/css/");
registry.addResourceHandler("/plugins/**","/plugins/");
}
}
十二、纯注解SSM整合(补)
①:整合配置
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
2. 创建配置文件 |
|
@Configuration
@ComponentScan("com.it.service")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MyBatisConfig.class})
public class SpringConfig {
}
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource datasource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
public class MyBatisConfig {
@Bean
public SqlSessionFactoryBean sessionFactory(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.it.domain");
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.it.dao");
return configurer;
}
}
@Configuration
@ComponentScan("com.it.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis_demo2?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
②:功能模块开发
create table books(
id int auto_increment primary key ,
type varchar(20) not null ,
name varchar(50) not null ,
description varchar(255)
)
insert into books (type, name, description)
VALUES ('计算机理论', 'Spring?实战第5版', 'Spring入门经典教程,深入理解Spring.原理技术内幕'),
('计算机理论', 'Spring5核心原理与30个类手写实战', '十年沉淀之作,手写Spring精华思想'),
('计算机理论', 'Spring5设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式'),
('计算机理论', 'Spring MVC+MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手'),
('计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握)ava基础的读者'),
('计算机理论', 'Java核心技术卷1基础知识(原书第11版)', 'Core Java第11版,Jolt大奖获奖作品,针对ava SE9、10、11全面更新'),
('计算机理论', '深入理解Java虚拟机', '5个维度全面剖析VM,大厂面试知识点全覆盖'),
('计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉'),
('计算机理论', '零基础学ava(全彩版)', '零基础自学编程的入门图书,由浅入深,详解)va语言的编程思想和核心技术'),
('市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中'),
('市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍'),
('市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
2. 创建实体类 |
|
public interface BookDao {
@Insert("insert into books (type, name, description) values (#{type}, #{name}, #{description})")
public int save(Book book);
@Update("update books set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
public int update(Book book);
@Delete("delete from books where id = #{id}")
public int delete(Integer id);
@Select("select * from books where id = #{id}")
public Book getById(Integer id);
@Select("select * from books")
public List<Book> getAll();
}
public interface BookService {
public boolean addBook(Book book);
public boolean updateBook(Book book);
public boolean deleteBook(Integer id);
public Book getBookById(Integer id);
public List<Book> getAllBooks();
}
5. 创建BookService实现类BookServiceImpl |
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public boolean addBook(Book book) {
return bookDao.save(book) > 0;
}
@Override
public boolean updateBook(Book book) {
return bookDao.update(book) > 0;
}
@Override
public boolean deleteBook(Integer id) {
return bookDao.delete(id) > 0;
}
@Override
public Book getBookById(Integer id) {
return bookDao.getById(id);
}
@Override
public List<Book> getAllBooks() {
return bookDao.getAll();
}
}
5.2 IDEA检查自动装配报错 |
|
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean addBook(@RequestBody Book book) {
return bookService.addBook(book);
}
@PutMapping
public boolean updateBook(@RequestBody Book book) {
return bookService.updateBook(book);
}
@DeleteMapping("{id}")
public boolean deleteBook(@PathVariable Integer id) {
return bookService.deleteBook(id);
}
@GetMapping("/{id}")
public Book getBookById(@PathVariable Integer id) {
return bookService.getBookById(id);
}
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
}
③:接口测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
public void addBook() {
Book book = new Book(0,"计算机类","Java核心卷Ⅱ","从入门到精通");
boolean b = bookService.addBook(book);
System.out.println(b);
}
@Test
public void updateBook() {
Book book = new Book(13,"计算机类","Java核心卷Ⅲ","从入门到秃顶");
bookService.updateBook(book);
}
@Test
public void deleteBook() {
boolean b = bookService.deleteBook(13);
System.out.println(b);
}
@Test
public void getBookById() {
Book book = bookService.getBookById(1);
System.out.println(book);
}
@Test
public void getAllBooks() {
List<Book> allBooks = bookService.getAllBooks();
for (int i = 0; i < allBooks.size(); i++) {
System.out.println(allBooks.get(i));
}
}
}
2. 表现层接口测试 |
|
④:事务管理
1. 开启注解事务驱动 |
|
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
3. |
|
⑤:乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
return new Filter[]{filter};
}
⑥:表现层与前端数据协议实现
1. 在controller包下创建Result用于封装数据 |
|
2. 在controller包下创建Code类定义所有的状态码值 |
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
}
@RestController
@RequestMapping("/books")
@Transactional
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result addBook(@RequestBody Book book) {
boolean flag = bookService.addBook(book);
return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@PutMapping
public Result updateBook(@RequestBody Book book) {
boolean flag = bookService.updateBook(book);
return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@DeleteMapping("{id}")
public Result deleteBook(@PathVariable Integer id) {
boolean flag = bookService.deleteBook(id);
return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
}
@GetMapping("/{id}")
public Result getBookById(@PathVariable Integer id) {
Book book = bookService.getBookById(id);
Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
String msg = book != null ? "" : "数据查询失败,请重试!";
return new Result(code, book,msg);
}
@GetMapping
public Result getAllBooks() {
List<Book> bookList = bookService.getAllBooks();
Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
String msg = bookList != null ? "" : "数据查询失败,请重试!";
return new Result(code, bookList,msg);
}
}
⑦:异常处理
01. 异常处理器
1. 在controller包下创建ProjectExceptionAdvice类 |
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result doException(){
return new Result(666,null,"出异常啦");
}
}
2. 测试(在根据id查询Book方法中制造一个异常) |
|
02. 异常处理方案
1. 创建exception包并在包内创建SystemException(系统异常)类和SystemException(业务异常)类 |
|
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
2. 定义异常状态码Code(在Code类添加以下代码) |
public static final Integer SYSTEM_ERR = 50001;
public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
public static final Integer BUSINESS_ERR = 60002;
3. 模拟异常代码 |
|
@Override
public Book getBookById(Integer id) {
if(id == 1){
throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐心");
}
try {
int i = 1 /0;
}catch (Exception e) {
throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试");
}
return bookDao.getById(id);
}
3. 修改异常处理器(ProjectExceptionAdvice)中的代码 |
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException e){
return new Result(e.getCode(),null,e.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException e){
return new Result(e.getCode(),null,e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result doException(){
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试");
}
}
⑧:放行静态资源
1. 在config包下创建SpringMvcSupport类 |
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
2. 将SpringMvcSypport类加入到SpringMvcConfig中 |
|
十三、拦截器
①:拦截器入门
1. 创建ProjectInterceptor类(定义拦截器) |
|
@Controller
public class ProjectInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle~~~~");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle~~~~");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion~~~~");
}
}
|
2. 配置执行哪些请求时进行拦截(在SpringMvcSupport)添加一部分代码 |
|
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
}
②:简化以上开发
1. 直接在SpringMvcConfig类中实现WebMvcConfigurer接口(但有侵入的缺陷) |
|
@Configuration
@ComponentScan({"com.it.controller","com.it.config"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer{
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
}
③:拦截器参数
## ④:拦截器链配置
1. 在创建一个拦截器 |
|
@Controller
public class ProjectInterceptor2 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle~~~~222");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle~~~~222");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion~~~~222");
}
}
2. 将拦截器2加入到SpringMvcConfig中 |
|
@Configuration
@ComponentScan({"com.it.controller","com.it.config"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer{
@Autowired
private ProjectInterceptor projectInterceptor;
@Autowired
private ProjectInterceptor2 projectInterceptor2;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
registry.addInterceptor(projectInterceptor2).addPathPatterns("/books", "/books/*");
}
}