SpringMVC操作的是程序的三层结构中UI层的后台部分
一、创建SpringMVC程序
1、开发SpringMVC需要的jar包:
spring-aop spring-bean spring-context commons-logging
spring-core spring-web spring-webmvc
2、创建配置文件springmvc.xml
选择常用的命名空间:beans,aop,context,mvc
3、开发流程
普通的servlet流程:
请求-url-pattern-交给对应的servlet去处理
以springmvc代替servlet的流程:
配置一个SpringMVC自带的servlet,
即在中配置org.springframework.web.servlet.DispatcherServlet,并配置
/
代表拦截所有并交给SpringMVC处理。
通过
contextConfigLocation
classpath:springmvc.xml
指定springmvc配置文件的路径。
如果要省略,须把springmvc配置文件放到默认路径:WEB-INF中,并根据
…中的值把
文件名改为…-servlet.xml
通过注解把普通类变为servlet,在类前添加@Controller注解即可
4、补充
@RequestMapping(value="…",method=…,params=…)
value指定映射名称,它还有ant风格的请求路径,如 ?代表单个字符,
*任意个字符(0或多个),**代表任意路径
@RequestMapping(value=“x1/a?c/a”)
在访问…/x1/a?c/a时能用任意单个字符替换?访问同一个页面,如…/x1/asc/a和…/x1/abc/a都可以
@RequestMapping(value="x1//a")
在访问…/x1//a时能用任意字符(不限个数)替代*访问同一个页面,如…/x1/aaa/a和…/x1/aaaaa/a都可以
@RequestMapping(value="x1//a")
在访问…/x1//a时能用任意目录结构代替**访问同一个页面,如…/x1/s/c/q/w/a和…/x1/qwe/a都可以
method指定请求方式
常见的有get,post,delete,put,如RequestMethod.POST
params指定name标签中的值
如params={“xxx=yyy”,“aaa”!=“bbb”,"!ccc"}
此时映射该方法的链接里需要有
不能有
这个可有可无,若有的话,则打开链接后需在xxx的输入框中输入yyy,在aaa的输入框中输入除bbb之外的数据才能成功运行该方法
可以添加在类和方法前面
若只在方法前添加,则映射时只需填括号中的内容,若两者都添加,则在映射该方法时须添加类的命名和/
如在类前@RequestMapping(value=“class”),在方法前
@RequestMapping(value=“method”),映射该方法时需要填写 class/method
@PathVariable
可以用来动态传值(仅限于get提交方式)
在java文件中创建使用该注解方法
@RequestMapping(value = "hello/{name}")
public String hello(@PathVariable("name") String name){
System.out.println(name);
return "success";
}
// @RequestMapping(value = “hello/{name}”)中的{name}会接受前端传来的参数,并把参数传给PathVariable(“name”)里的“name”,最后再传给后面的String name中的name
在index.jsp文件中使用该超链接
hello
开启tomcat后到浏览器使用进入项目的页面,点击hello超链接后会程序会把world传给java文件,此时控制台会打印world
二、SpringMVC的Rest编程风格
1、提交方式一般为GET POST DELETE PUT
普通浏览器只支持get和post方式,其他请求方式如 delete/put请求是通过 过滤器新加入的支持
2、实现put/delete请求(请求方式为post)
a、增加过滤器
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>
org.springframework.web.filter.HiddenHttpMethodFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
b、前端表单
**请求方式为post**通过隐藏域的value值 设置实际的请求方式
c、控制器
@RequestMapping(value = "TestRest/{id}",
method = RequestMethod.DELETE)
@ResponseBody()
public String Delete(@PathVariable("id") Integer id) {
System.out.println("delete:删" + id);
return "success";
}
通过method = RequestMethod.DELETE,匹配具体的请求方式
此外,当映射名相同时@RequestMapping(value = “TestRest”,可以通过method处理不同的请求
d、过滤器中 处理put|delete请求的部分源码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter((ServletRequest)requestToUse, response);
}
原始请求:request,该请求默认只支持get post header
但是如果是“POST”并且有隐藏域
则过滤器 将原始的请求 request加入新的请求方式DELETE,并将原始请求 转为 requestToUse 请求(request+Delete请求),最后将requestToUse 放入请求链中,后续使用request时,实际就使用改造后的requestToUse
3、RequestParam()
@RequestParam("uname") String name,
@RequestParam(value = "value=uage",required = false,defaultValue = "23") Integer age
@RequestParam(“uname”):接受前台传递的值,等价于request.getParameter(“uname”);
required = false:该属性 不是必须的
defaultValue = “23”:默认值23
4、@RequestHeader:获取请求头信息
public String testRequestHeader(@RequestHeader("Accept-Language") String al)
通过@RequestHeader("Accept-Language") String al
获取请求头中Accept-Language值,并将值保存在al变量中
5、@CookieValue
前置知识
服务端在接受客户端第一次请求时,会给该客户端分配一个session(该session包含一个sessionId),并且服务端会在第一次相应客户端时,将该sessionId赋值给JSESSIONID并传递给客户端
左边客户端,右边服务端
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-um24UiE2-1616404077775)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210222220611128.png)]
2、通过mvc获取服务端传给客户端的cookie的值
public String testCookieValue(@CookieValue("JSESSIONID") String jsessionid)
跟@RequestHeader的流程一样
@CookieValue("JSESSIONID") String jsessionid
6、SpringMVC处理对象
7、小结:SpringMVC处理各种参数的流程/逻辑
三、模型数据传递
1、mvc的数据传输模型
用户从view输入31传给Controller,Controller将31传给StudentService.queryStudent()查询31号学生并获得具体数据,之后再将数据传递给view,此时需要保存的数据有V和M
2、跳转时要带数据:V、M使用的方式
1、把数据放在request作用域里
1、ModelAndView
后端页面:
前端页面:
2、ModelMap
前端页面同ModelAndView
后端页面:
3、Map
前端页面同ModelAndView
后端页面:
4、Model
前端页面同ModelAndView
后端页面:
2、@SessionAttributes
将数据放入session域中
1、指定单个对象:
2、指定一个类,即该类产生的对象都会放在session域中
3、@ModelAttribute
在更新时使用
1、原理图
将zs的值修改为ls并且其他数据都保存
2、实现效果
将上方student的值传给的下方的student中
3、实现过程
通过@ModelAttribute修饰的方法,会在每次请求前先执行;
并且该方法的参数map.put()可以将 对象 放入 即将查询的参数中
必须满足约定:map.key(k,v)中的k 必须是即将查询的方法参数 的首字母小写
如下图的"student"和Student
如果不一致,需要通过@ModelAttribu来指定
四、视图与解析器
1、流程
无论Controller的返回值是哪种,它都会转成ModelAndView对象,并会交给视图解析器(ViewResolver)解析,解析完成后就变成视图,视图经过视图渲染后就能被用户看到。
2、视图、视图解析器
1、视图的顶级接口:View
2、视图解析器:ViewResolver
3、常见的视图和解析器
InternalResoureceView、InternalResourceViewResolver
3、JstlView
1、继承自InternalResoureceView
springMVC解析jsp时 会默认使用InternalResoureceView,如果发现jsp中包含了jstl语言会自动转为JstlView
2、作用
可以解析jstl / 实现国际化操作
3、国际化
针对不同地区、不同国家,进行不同的显示
4、实现国际化步骤
a、创建资源文件
需满足的条件
格式为:基名_____语言_____国家.properties 或者 基名_____语言_____.properties
基名一般为base或i18n
如base_zh_CN.properties
属性值寻找规律:
中文资源文件需要以ASCII码的形式,即如下图
可通过在命令行运行jdk的bin目录中的native2ascii.exe,如下图
b、配置springmvc.xml,加载资源文件
c、流程图
d、通过jstl使用国际化
需要jar包:
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
4、常见功能
1、简化处理流程
正常的处理流程:index.jsp -> Controller(@RequestMapping) -> success.jsp
简化后的处理流程:index.jsp -> success.jsp ,即省略掉Controller(@RequestMapping)
可以用SpringMVC实现:
<mvc:view-controller path="请求路径" view-name="返回的视图名称">
如下图:
当Controller的路径也相同的话,会跳到标签,忽略Controller
如果想让@RequestMapping(“a”) 和 共存,需要加入一个注解:
<mvc:annotation-driven></mvc:annotation-driven>
5、指定请求方式
指定后不会被视图解析器加上前缀后缀,需要自己把路径写全
使用这种方式后国际化会失败
1、请求转发
返回时用forward指定
格式为:return "forward":具体路径;
2、重定向
返回时用redirect指定
格式为:return "redirect":具体路径;
6、处理静态资源
1、静态资源
html、css、js、图片、视频等。不能与用户交互。
2、动态资源
可以与用户交互,因为时间/地点的不同 而结果不同的内容(百度:天气)
3、springmvc中的静态资源
1、问题
在springmvc中,如果直接访问静态资源会404
原因如下:
所有请求被通配符”/“拦截,进而交给springmvc的入口DispatcherServlet去处理
DispatcherServlet处理方式:找该请求映射对应的@RequestMapping
将静态资源放在初始目录下后的链接为:
http://localhost:8080/springMVCProject/img.png
经过DispatcherServlet处理后会变成
@RequestMapping(“img.png”)
这样就找不到静态资源了
2、解决方案
如果是需要springmvc处理的,则交给@RequestMapping()处理;
如果不需要springmvc处理的,则使用tomcat默认的Servlet去处理。
实现方法:
1、将放置静态资源的目录设置为资源目录
2、在springmvc.xml中增加两个配置即可
<mvc:default-servlet-handler></mvc:default-servlet-handler
>
( 该注解会在springmvc接收到一个没有对应的@RequestMapping()的请求时,将该请求交给服务器默认的servlet去处理(直接访问))
和<mvc:annotation-driven></mvc:annotation-driven>
(默认的Servlet处理过程:如果有 对应的请求拦截,则交给相应的Servlet去处理,如果没有对应的Servlet,则直接访问)
Servlet访问过程如下图:
tomcat默认的Servlet位置:\conf\web.xml的DefaultServlet
7、类型转换
1、类型转换图
2、springmvc自带的常见类型转换器
public String Delete(@PathVariable("id") String id)
既可以接收int类型数据id 也可以接收String类型的id
3、自定义类型转换器
1、编写自定义类型转换器的类
实现Converter接口
2、将编写的转换器加入到springmvc中
3、注意问题
后端需要加上@RequestParam()来指定前端传递的内容,否则会跟自带的类型转换器冲突,导致无法判断
五、数据格式化
1、实现步骤
1、配置
2、通过注解使用
1、@DateTimeFormat()
日期格式化注解
2、@NumberFormat()
数字格式化注解
3、获取错误信息
2、FormattingConversionServiceFactoryBean的功能
既可以实现格式化,又可以实现类型转换
六、错误消息处理和数据校验
1、错误消息处理
将错误信息放到map中并通过request域传给前端
后端:
此时需要验证的数据是Student中的birthday,SpringMVC要求 如果校验失败 则将错误信息 自动放入该对象之后紧挨着的 BindingResult中。即下图中的Student student,BindingResult result
不能有其他参数
前端:
2、数据校验
1、JSR 303 提供的标准注解如下表
2、Hibernate Validator
1、需要的jar包
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
2、配置
<mvc:annotation-driven></mvc:annotation-driven>
此时该注解的作用:要实现Hibernate Validator/JSR303 校验(或者其他各种校验),必须实现SpringMVC提供的一个接口:ValidatorFactory
但SpringMVC已经实现过了,LocalValidatorFactoryBean是ValidatorFactory的一个实现类。
<mvc:annotation-driven></mvc:annotation-driven>
会在springmvc容器中自动加载一个LocalValidatorFactoryBean类,因此可以直接实现数据校验。
3、使用注解
在属性前添加注解
在校验的Controller中,给校验的对象倩增加@Valid
七、处理json数据
1、添加注解
1、@ResponseBody
当控制器为@Controller时,默认返回视图,需要在方法前添加注解@ResponseBody,添加后就不会走视图解析器,而是直接返回一个字符串
2、@RestController
添加后整个控制器就默认返回字符串格式
2、处理乱码
1、只处理一个
在@RequestMapping中添加produces = "application/json;charset=utf-8"
2、配置所有
在springmvc.xml文件中添加
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"></constructor-arg>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"></property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
3、Jackson
1、添加依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
2、使用
1、传递一个对象
2、传递一个集合
3、处理时间对象
时间解析后的默认格式为:Timestamp,也就是时间戳
解决方法:
1、使用SimpleDateFormat转换时间格式
2、使用ObjectMapper自带的格式转化
4、fastjson
1、添加依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2、常用类
3、使用
4、其他操作
八、文件上传
1、添加依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
2、实现接口
1、需要实现MultiparResolver接口
2、SpringMVC提供该接口的实现类
CommonsMultipartResolver
3、具体步骤
1、配置CommonsMultipartResolver
将其加入springioc容器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 上传单个文件的最大值,单位Bytes;如果-1,表示无限制 -->
<property name="maxUploadSize" value="102400000"></property>
</bean>
注意:
id值不能变,原因:springIoc容器在初始化时,会自动寻找一个ID="multipartResolver"的bean,如果有,自动将该bean配置到ioc容器里,如果没有,则会忽略该bean
2、处理方法
后端
前端
九、拦截器
1、原理
原理跟过滤器相同
要想实现拦截器,必须实现接口HandlerInterceptor
结构图
流程图:
2、添加依赖
需要添加HttpServletRequest 和 HttpServletResponse需引用的依赖包
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
3、编写接口实现类
4、配置
将自己写的拦截器 配置到springmvc容器中
1、默认
2、配置指定拦截器
5、多个拦截器的过程
十、异常处理
1、简介
1、异常实现接口
HandlerExceptionResolver
2、接口实现类
1、ExceptionHandlerExceptionResolver
主要提供了@ExceptionHandler注解,并通过该注解处理异常
2、ResponseStatusExceptionResolver
自定义异常显示页面,通过注解@ResponseStatus实现
3、DefaultHandlerExceptionResolver
springmvc自带的默认异常处理器,提供了以下的异常处理
4、SimpleMappingExceptionResolver
通过配置来实现异常处理
2、使用
1、@ExceptionHandler注解
在方法前使用该注解,转为专门异常处理的方法(只能捕获当前类中的异常)
//在注解的"{}"中写入要捕获的异常,控制器就会自动捕获,可以写多个异常
//如果在本类中捕获到相对应的异常,就自动转入该方法,相当于catch
//该方法可以捕获本类中 抛出的ArithmeticException异常
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handlerArithmeticException(ArithmeticException e){
ModelAndView mv = new ModelAndView("error");
System.out.println(e);
mv.addObject("e",e);
return mv;
}
2、@ControllerAdvice注解
在类前添加该注解,使整个类转为专门处理异常的类,这样其他类出现异常也就能处理(需要将该类添加进扫描包)之后在要处理异常的方法前加@ExceptionHandler注解即可
3、@ResponseStatus
可在类和方法前添加
- 下面演示类
自定义一个异常类并在其前加上@ResponseStatus注解,在value中写上异常编号,在reason中写上异常描述信息
通过抛出该异常显示信息
前端显示信息
4、通过springmvc配置
3、异常处理路径
处理先后顺序:
- 当前类 ——> 其他类 ——> 配置
- 如果类中有多个能处理该异常的方法,则是子异常优先
如下图中有两个添加处理异常注解的方法,其中ArithmeticException是Exception的子类,如果出现ArithmeticException异常,会被handlerArithmeticException捕获