# SpringMVC
**Repository Path**: xgdtianxian/SpringMVC
## Basic Information
- **Project Name**: SpringMVC
- **Description**: SpringMVC
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-11-08
- **Last Updated**: 2024-05-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
SpringMVC
一 .MVC
MVC是软件设计的一种架构模式
M:model 模型 包含 数据和 行为两部分
功能:1.承载需要显示在页面里的数据(java实体 User,Book,Writer)
功能:2 执行具体的业务操作,数据库操作(Service对象和Dao的对象)
V:view 视图:负责进行模型的显示,就是用户看到的界面.(jsp html)
C:controller 控制器:
1.负责 接受请求中的 数据
2.委托给模型进行处理(控制器调用 service 再调用dao)
3.收到处理后的数据以后把数据转交给 视图,由视图来负责显示。
ps:框架之前 ——>Servlet
SpringMVC -----> SpringMVC 的 Controller
二.SpringMVC
1.Spring框架的一部分
2.构建在Servlet之上的
3.轻量级的java的MVC框架
三.SpringMVC快速入门(略)
四.SpringMVC工作原理:
SpringMVC的所有设计都是 围绕 DispatcherServlet 来进行设计。
1.客户端发起请求被DispatcherServlet 捕获
2.ds 调用HandlerMapping 根据注解配置,查找要被执行的handler
3 由hm 返回handler 给 ds
4 ds 调用 HandlerAdapter,给传递Handler
5.由HandlerAdapter 调用handler里的方法
6.Handler(我们自己写的Controller,后端处理器)执行方法,返回
ModelAndView对象(模型和视图)
7.HandlerAdapter 把ModelAndView 返回给Ds
8.Ds传递mv给ViewResolver(视图解析器),根据字符串获取相关的视图(jsp html)
9.视图解析器返回 View(视图对象)给Ds
10.ds 对 view进行渲染(得到纯静态的html、json)
11.ds把静态的html 返回给客户端。
五,请求参数处理:
1.请求中的中文乱码问题:
a.对于POST请求而言,可以使用SpringMVC提供的字符编码过滤器 CharacterEncodingFilter
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
characterEncodingFilter
springMVC
b.对于 GET请求而言,在Tomcat的安装目录下的 config /serve.xml中
2.请求参数为标量(字符串 数字 日期)
a.请求的方法中,形参的名字和 参数的参数名(name属性)完全一致即可
ps:对于 日期类型(Date),默认要求 日期的格式为: yyyy/MM/dd hh:mm:ss
b. 在形参前 加上 @RequestParam(value="请求参数的参数名",required="该参数是否必填",defaultValue="默认值")
RequestParam 会把 指定参数名的 请求参数 赋值给 形参(不要求两个名字一致)
3.如果方法的参数 是一个 POJO对象
请求参数的名字 和 对象的属性名一样就可以了,和方法的形参名 无关(不需要写成 形参名.属性名的格式),就可以自动的吧请求的参数,
转换POJO对象的 属性的属性值。
如果POJO的某个属性 是另外一种对象b,请求参数的参数名:属性名.属性
4. 如果方法的参数 是一个 数组/集合
请求参数中,name属性和数组的名字一致即可 test05?hobbies=sing&hobbies=dance(不加索引)
集合,集合需要放在对象的属性出现,name属性为 集合名字[索引]
5. 如果对象的属性是一个 map集合
请求 参数中 name属性 应该是 对象属性名[key]
6. 获取 请求头中的数据
@RequestHeader("请求头的名字") String 形参
7. 获取 请求中 Cookie中的数据
@CookieValue("cookie的name") String 形参
8. 获取ServletAPI
简单来说就是获取 request response session application 这几个对象
a. 项目导入 servlet-api的jar包
b. 直接在 方法中,加入 相关的参数声明
public String getApi(HttpServletRequest request,HttpServletResponse response,HttpSession session){
ServletContext application = request.getServletContext();
}
六.请求映射处理
1.RequestMapping 可以放在Controller类上面,表示在访问 该Controller下的所有方法时,应该加上此时指定的路径
@RequestMapping("/user")
public class UserController(){...}
2.RequestMapping 还可以放在Controller里的方法上(注意+/) ("/addUser")
完整的访问路径应该是 : 类上配置的路径+方法上的路径 ("项目名/user/addUser")
ps: 方法中 返回页面时,+"/index.jsp" 表示 项目的根目录出发的 index.jsp
3.RequestMapping 可以通过属性配置请求方式等信息
@RequestMapping(value="/请求路径",method="{RequestMethod.POST,RequestMethod.GET}",params={"username","!password"},headers={"user-agent"}")
method-> 设置请求方式
params-> 设置请求中参数的要求
headers-> 请求头中数据的要求
4. 可以使用 @PostMapping @GetMapping @DeleteMapping @PutMapping 去接受特定方式的请求。
5. 获取url目录级别的参数(即在url地址中,不通过 ?参数名=值 这种形式传参)
https://www.acfun.cn/v/ac39779046(视频id)
https://blog.csdn.net/weixin123/article/details/130389856
账号 文章id
@RequestMapping("/user/{id}")
public String getUser(@PathVariable("id") int userId){
// 可以把url地址中 {id}占位符的这部分,赋值给形参userId
}
@RequestMapping("/user/{username}/{password}")
public String getUser2(User user){
// 占位符的名字要和对象的属性名一样
}
七.REST
REST是一种架构模式, restful url指的是 rest这种风格的 URL链接
客户端到服务器资源
restful的url 通过 名词 + 方法的请求方式来确定 url地址的功能
localhost:8080/library/user/1
GET->查询
POST->添加
DELETE->删除
PUT->修改
单体应用中:
HTML语言只支持 POST/GET请求
HTTP协议 支持 POST、GET、DELETE、PUT请求
ajax/axios 支持 DELETE 请求和 PUT请求
表单发起DELETE/PUT请求
1 请求方式 改为 POST
2 表单中加入
3 web.xml中 加入 HiddenHttpMethodFilter过滤器
4.方法中使用 @DeleteMapping @PutMapping
5.如果要在controller中做页面跳转
a.tomcat 7.0以前
b.jsp + isErrorPage = true
c.跳转方式使用重定向 /项目名/资源。。
八.静态资源访问
DispatcherServlet(前端控制器)拦截了 除了 jsp之外的所有请求("/") ,导致再页面中 引入 css js html 图片这些静态资源都会被拦截,
而Controller里找不到与其对应的资源,会出404. 而这些资源并不需要经过Controller
处理方法1;
配置 默认TomcatServlet,当SpringMVC404时,请求交由Tomcat来处理。
方式2:配置静态资源直接访问
九.响应处理
9.1 视图解析器
controller中返回一个字符串,根据解析器找到对应的视图
9.2 视图控制器
对于部分jsp页面,不希望通过Controller进行访问,而又被放在了web-inf。
9.3 向request作用域存入数据
a. 直接在方法中加入 HttpServletRequest request. request.setAttribute();
b. 在方法中 加入 Model 或 ModelMap 或 Map,直接调用他们的方法存入数据.本质都是通过(BindingAwareModelMap 来存)
c. 通过ModelAndView,即方法返回一个对象,在modelAndView里;
mv.addObject(数据);
mv.setViewName(视图名);
d.特殊的,如果springMVC方法中进行了参数绑定,并且以转发到某一页面,可以在页面中 ${param.key}取出
9.4 向 session作用域 存取数据
a. 直接使用HttpSession
获取Session : a.1 直接在方法中 加入 HttpSession
a.2 在controller 声明一个 HttpSession session 通过@Resource 进行自动注入。
@Resource
private HttpSession session
b. @SessionAttributes("msg");
b.1 放在Controller类上
b.2 当前类下的所有方法,只要向Model中 存入msg时,都会同时向session中存入一份
b.3 当前类的所有方法,在执行时,都会尝试从session中取出msg,并再model里存入一份
c.@SessionAttribute("msg");
c.1 放在方法形参前面,执行方法时,会从session中 取出一个msg,并赋值给形参
c.2 required = true 表示session必须有msg,没有会报错
c.3 required = false 如果session中没有,会赋值null
9.5 转发和重定向
Controller 里的方法 通过 return + "视图名" 默认是转发
转发: return "forward:/index.jsp" /表示 项目级别的根目录 (web目录下),此时必须写完整路径名(不会经过视图解析器)
重定向: return "redirect:/index.jsp" 同上。
9.6 @ModelAttribute
1. 放在 方法之上,不加任何参数,该Controller下的所有方法在执行之前,都会先执行 @ModelAttribute()
标记的方法
2. 放在方法上,标记的方法中,返回值类型为void,并且方法的参数中加入 Model model,
那么在model中加入的其他数据,可以在该Controller的所有方法里 都能取到
@ModelAttribute
public void init(Model model){
model.addAttribute("msg","hello");
}
3.放在方法上,@ModelAttribute("名字A"),标记的方法的返回值,会被存入到Model,名字为"名字A"
相当于执行了 model.addAttribute("A",方法返回值);
@ModelAttribute("msg")
public String init(){
return "hello";
}
4.放在Controller的方法的 形参前
public String update(@ModelAttribute("u") User user){
// 从model中取出变量 u,和前端传过来user 对象 进行合并
// 在u的基础上,前端传过来的user 有的属性就覆盖,没有则维持不变。
}
9.7 session 获取的线程安全问题
a.SpringMVC controller是单例的
b.直接在方法中加入 参:HttpSession session, 线程安全的,方法的运行在栈内存,每次这个方法被调用都是独立的栈帧。不同的请求就是不同的会话。
c.使用Spring 在Controller里 声明一个 private HttpSession session属性,并通过@Autowired进行自动注入(按理来说是不安全的,因为单例的Controller 只有一个
session属性,只有一个空间来存储) 但是!它是线程安全的,Spring底层实际是把session绑定到线程。
d. 通过ModelAttribute()来获取Session,再传入controller里提前声明的session中,不安全。因为session是声明再类级别里的,共享变量,所以线程不安全
结论,再Controller的内部,由于是单例模式,所以不要声明 类级别的变量(属性,或者 静态属性),会存在线程安全问题
十:类型转换器
功能:按照自定义的规则,把前端传递过来的参数进行类型转换.
流程:
1.创建转换器类,实现Converter<源类型,目标类型>接口
2.重写 convert方法,制定转换规则
3.配置 conversionService bean 类型: ConversionServiceFactoryBean
并在其中注入 converters属性 注入我们自己的转换器
4.配置
ps:bean的id 必须叫conversionService
十一:数据格式化
SpringMVC 运行 我们按照指定的格式进行传参,或者是在页面显示某一个属性时间,按照指定的格式进行显示。
1.直接在 实体类的属性上,添加相关的注解
2.配置类型转换服务 为 FormattingConversionServiceFactoryBean
这个服务bean 同时支持 类型转换器 和 数据格式化。
相关注解:
1.@DateTimeFormat 可以用于 java中的 Date类型的属性上
@DateTimeFormat(pattern ="日期的格式",fallbackPattern={"备用格式"})
2.@NumberFormat 用于格式化数字类型
@NumberFormat(style="NumberFormat.Style.CURRENCY",pattern="¥#,###.##")
style 包含 NUMBER
CURRENCY 货币组织
PERCENT 百分比
pattern 中 #代表一位数字
ps:如果希望在jsp页面中 按照格式化的注解来输出对象的属性
导入 spring标签库
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
十二:数据校验
指的是简化后端的非业务型的输入校验
a.导入jar包 hibernate-validator, 实现了 JSR303的校验标准
b.在需要进行验证的属性上加上相关的注解:
@Null 必须为空
@NotNull 必须不为空
@AssortTure 必须为true
@AssortFalse 必须为false
@Min(value) 允许的最小值(>=)
@Max(value) 允许的最大值(<=)
@DecimalMin(value) 最小值
@DecimalMax(value) 最大值
@Past 必须为过去的时间
@Future 必须为将来的时间
@Pattern("regx") 必须满足指定的正则表达式
@Email 必须为邮箱格式
@Length (字符串的长度)
@NotEmpty (字符串必须非空)
@Range (被注解的元素必须在合适的范围内)
c.Controller的方法里,在需要进行校验的参数前 @Valid
d.方法中加入 BindingResult 来获取所有的错误信息
BindingResult的方法
hasErrors() 是否有错误信息
getFieldErrors() 获取所有的 属性错误信息 List
FieldError的方法:
getFiled() 获取没有通过校验的属性的属性名
getDefaultMessage() 获取错误的提示信息
ps:数据校验可以配合Spring 表单标签 进行简化
a.导入 spring form标签库
b 来表示一个表单
跳转到 这个页面的时候 request里 必须要有一个 名字叫 user的对象
来表示一个一般的输入框 path后跟对象的属性
来表示 username的 错误信息提示
c. 后端controller的方法中,直接使用 @Valid BindingResult,方法中不再需要自己来解析错误信息
十三: SpringMVC json处理
前置:
json对象,指的是 javascript格式描述的一个对象 {"userId":1,"username":"zhangsan"}
json字符串: 本质上是一个字符串符合json格式 '{"userId":1,"username":"zhangsan"}'
前端: JSON.parse(字符串) -> 把字符串转换成对象
JSON.stringify(对象) -> 对象转换成 json字符串
1.返回JSON(字符串)
a。导入json转换相关的jar包,负责把java对象转换成json字符串,把json字符串转换成java对象
(常用的 jackson 2.12.4 fastJson)
b. 在Controller的方法上 加上注解 @ResponseBody ,这时这个方法不在进行该页面跳转,只负责返回数据
。这种接口 叫做 服务型API
ps: 如果一个Controller的方法都是服务型API,那么可以直接在类上 使用 @RestController,不需要额外@ResponseBody
c. 方法的返回值直接返回需要的数据类型(Object),直接在方法的末尾return
ps:静态资源配置不可少
注解:
@JsonIgnore
放在 某个属性上,当这个对象转换成json字符串时,会忽略这个属性
@JsonFormat(pattern="yyyy-MM-dd")
private Date birthday
默认的 java date类型再转换成json字符串时,转换成时间戳,通过该注解,可以设置转换的日期格式
2.接受Json
a. 前端 需要 向 后端发起请求
a.原始的js
b.jquery的ajax
c.vue的 axios
b. 使用 ajax
$.ajax({
url:"请求地址",
type:“请求方式”,
data:"给后端发送的数据",
contentType:"设置前端给后端发送的数据格式(默认是表单,application/json)",
dataType:前端接收后端的数据的格式(预估)
success:function(data){
请求成功后响应的数据
}
})
c. 1如果前端发送的是 json字符串(json格式)
a.ajax 里 必须设置 contentType:"application/json",
b.后端使用 @RequestBody 把字符串 转换成java对象
c.前端不能使用 get请求,使用POST
2 如果 前端发送的是 一个对象,等效于用表单发起请求
a.contentType "application/x-www-form-unlencoded",可以不写
b. 后端不能用 @RequestBody
c. data里的数据实际被转换成了 key=value&key=value 这种格式
d. 可以使用 post get请求
如果要给后端发送集合 使用方式1
十四。上传和下载
下载的方式:
1.直接在a标签的地址中写要下载的文件路径
a.需要配置静态资源访问
b.不能进行权限控制
c.对于某些格式的文件会直接打开,而不是下载。
2.基于ServletAPI ,通过response对象获取到输出流
直接向客户端写回要下载的文件
@RequestMapping("/download01")
public void download01(HttpServletRequest request,HttpServletResponse response) throws IOException {
// 获取要下载的文件的真实路径(从盘符出发的路径)
String realPath = request.getServletContext().getRealPath("/file/简易.txt");
//创建一个 File表示 要被下载的文件路径
File file = new File(realPath);
//创建输入流来读取文件
FileInputStream ins = new FileInputStream(file);
//设定 响应的格式,告知输出流的文件以附件的形式打开,URLEncoder 确保下载的文件名中文正常显示。
response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode(file.getName(),"UTF-8"));
//获取 用于向客户端 返回数据的 输出流
OutputStream oos = response.getOutputStream();
//创建一个 缓冲区 用于装每次从输入流中读出来的信息,缓冲区可以减少 磁盘io的次数.
byte[] buffer = new byte[1024];
//文件复制
int len = 0;
while((len = ins.read(buffer))!= -1){
oos.write(buffer,0,len);
}
ins.close();
oos.close();
}
3.基于SpringMVC提供的 ResponseEntity 响应实体进行下载
,响应实体的构造方法中需要传入 要下载文件的完整字节流,
HttpHeaders 和 响应状态码
/*
* 基于 Spring提供的 ResponseEntity 进行下载,
* ResponseEntity用于表示 返回的实体。
* 潜在风险:一次性获取 完整的输入流中的数据,有可能造成内存溢出。
* */
@RequestMapping("/download02")
public ResponseEntity download02(HttpServletRequest request) throws IOException {
// 设置 要下载文件的真实路径
String realPath = request.getServletContext().getRealPath("/file/简易.txt");
//创建一个 file对象
File file = new File(realPath);
// 创建 一个 Http头文件
HttpHeaders headers = new HttpHeaders();
// 头文件中 设置客户端浏览器打开的方式
headers.set("content-disposition", "attachment;fileName=" + URLEncoder.encode(file.getName(), "UTF-8"));
// 创建对 下载文件的 输入流
InputStream ins = new FileInputStream(file);
// 创建一个 响应实体,并返回,需要传入 完整的输入流中的数据,响应头,和响应码
byte[] bytes = new byte[ins.available()];
ins.read(bytes);
return new ResponseEntity(bytes, headers, HttpStatus.OK);
}
上传:
1。导入相关的jar commons-fileupload
2. 在Spring容器中 加入 multipartResolver
//可以注入 最大文件大小 编码 每个文件大小等属性
3.表单中
4.Controller 使用 MultipartFile mf来接受用户上传的文件
有一组get方法获取文件的信息
mf.transferTo(File file/String path) 把文件复制到指定路径。
十五.SpringMVC拦截器
1.概念:
Interceptor拦截器 和过滤器类似,采用面向切面的思想,在Controller里的方法执行之前或者之后执行一些和主业务没有关系的公共功能
(权限/登录验证 日志处理 异常记录 性能分析)
2.步骤:
a.自定义 一个拦截器类 实现HandlerInterceptor接口
b.重写 接口的方法
preHandle 预处理方法,再Controller的方法执行之前执行(登录/权限 验证),返回true放行.false中断,不会再执行controller里的方法。
自行使用 request或者response 进行页面跳转。
postHandle 后处理方法,在controller的方法执行完毕之后,视图渲染之前(还没跳页面),可以对ModelAndView进行处理。
ps:如果controller出错,这个方法不会执行,所以不能做异常日志.
afterCompletion:请求处理完毕之后(试图已经渲染好),用于记录请求耗时,释放资源,异常记录,统一异常处理(转发)
c. 在容器中 配置拦截器
//会拦截所有的请求
// 配置具体的某一个拦截器
/login(具体某一个路径) /*(所有路径,但不包含二级路径) /**(所有包含二级) /user/* user下的所有请求
同上,注意添加放行静态资源
SpringMVC的拦截器 和 Servlet的过滤器 区别:
1.过滤器是基于函数回调,拦截器是基于java的反射机制
2.过滤器依赖于Tomcat,拦截器依赖SpringMVC
3.过滤器可以拦截所有的请求,而拦截器只作用于SpringMVC的controller
4.拦截器可以访问 Handler的上下文,而过滤器不行。
十六:SpringMVC 国际化:
给不同国家的用户,以不同样的语言文本呈现网站内容就叫做国际化,简称
i18n (Internationalization)
l10n (Localization) 本地化
a.通过修改浏览器语言设置国际化
1. 在resource下添加 国际化资源文件
i18n/login.properties 或 视图名_语言_地区.properties
资源文件中 key=value 多个语言的key保持一致
2. 配置使用属性资源文件
i18n/login --i18n/视图名
3.确保 jsp页面 是通过 Controller 进行访问,并且使用视图解析器
4.在jsp中 使用 输出对应的文字
5.修改所在区域
b.通过超链接来切换国际化
a. 发起任何请求时,在请求中携带 locale 地区参数
login?locale=zh_CN
login?locale=en_US
b.配置地区变更拦截器,会保存地区变更的信息
c. 修改 默认的 地区解析器
地区解析器:
AcceptHeaderLocaleResolver (默认) 根据浏览器的语言信息(请求头中的accept-language) 解析地区信息
SessionLocaleResolver 从session中获取 locale信息
CookieLocaleResolver 从Cookie中获取 locale信息
d.当任何一处改变了地区信息,那么接下来全部的操作都会使用相同的语言。
3.在Controller中的方法中如何获取 国际化资源文件中的文本
a.在Controller中 注入一个 MessageSource(容器中得有)
@Resource
private MessageSource messageSource
b.在Controller中的方法中 传入Locale locale参数
c.messageSource.getMessage("key",null,locale) 获取对应语言的对应key的文本.
4.数据校验国际化实现:
a.校验部分使用规则不变
b.在国际化资源文件中 以 校验规则(注解名).对象名.属性="错误消息" 格式编写资源文件
Length.user.username=用户名长度。。。
c.如果不使用Spring的表单标签,那么自行在controller的方法中,根据出错的表单项目,取对应的消息
如果使用 Spring表单标签,则不需要做任何处理 直接使用 取对应的错误消息
十七:SpringMVC 统一异常处理
方式一:针对某一个Controller下的所有方法,在执行时发生的异常进行处理
a.自定义一个 异常处理方法,返回值类型必须为ModelAndView,
b.使用 @ExceptionHandler(异常的类型) 来捕获具体的异常
c.在方法中设置 返回的异常视图即可,选择性加上异常信息。(或者日志记录 输出 异常信息)
4.当有多个异常处理方法时,会使用范围更精准的方法。
方式二:全局异常捕获
a.创建一个全局的异常处理类,使用 @ControllerAdvise,会处理所有Controller中的异常.
b。@ExceptionHandler + 异常处理方法(同方式一)
c.当同时存在全局异常处理和单个Controller里的异常处理,会优先使用单个Controller中的异常处理。
ps:
request.getHeaders("X-Requested-With") 不为空时,说明是异步请求
ModelAndView mv = new ModelAndView(new MappingJacksonToJsonView());
通过此方式初始化的 mv,不再做页面跳转,直接返回json试图(会把mv里的数据,直接转换陈json字符串返回给前端,用于异步请求)
方式三: 只用于设置 Controller方法 执行过程中产生的异常,并进行页面跳转
//默认 错误视图
404处理:
在web.xml中
404
/404.jsp
Swagger2 应用
1.swagger2 可以用于自动生成 接口的文档,可以用于接口的测试
流程:
1. 导入相关的jar包
2. 编写swagger的配置类
3. 在容器中添加 swagger的配置类和swagger需要的静态资源访问
4. 在controller类 方法 参数上使用一些注解
5. 通过 项目名/swagger-ui.html 访问页面
常用注解:
@Api(value="名字",tags="标签名(会打组,会覆盖value)")
用在Controller的 类上面。
@ApiOperation(value="名字",notes="提示信息",httpMethod="设置请求")
用在Controller的方法之上
@ApiModel(value="名字",description="介绍文字")
放在bean entity的实体类上
@ApiModelProperty(name="名字",value="名字",notes="介绍")
用在实体类的属性上
@ApiParam(name="page",value="提示",required="是否必填")
用在 controller方法里的,参数前。