Json
Json请求
请求方法:Post
Content-Type: application/json
data: Json字符串
构造Json请求
使用Postman来构造
引入依赖
jackson
JavaBean或Map来接收
//{"username":"admin123","password":"admin123"} @RequestMapping("login") //public BaseRespVo login(JsonUser user) {//localhost:8080/json/login?username=admin123&password=admin123 public BaseRespVo login(@RequestBody JsonUser user) { return BaseRespVo.ok(); } @RequestMapping("login2") public BaseRespVo login2(@RequestBody Map user) { return BaseRespVo.ok(); }
场景
使用Map来接收,主要场景是参数比较少。参数类型不容易固定
其他场景都用JavaBean
@RequestMapping("login2") public BaseRespVo login2(@RequestBody Map user) { Object age = user.get("age"); //age究竟是什么类型呢? return BaseRespVo.ok(); }
其他参数
Request/Response
如果你需要使用request和response可以直接放到Handler方法的形参中,可以直接使用,原因是会经过doGet或doPost,这个时候就会拿到request和response
//localhost:8080/other/hello?username=songge @RequestMapping("hello") public BaseRespVo hello(HttpServletRequest request, HttpServletResponse response) { String username = request.getParameter("username"); return BaseRespVo.ok(username); }
Model
Handler方法的返回值为字符串,如果没有增加@ResponseBody,意味着要处理ModelAndView,返回值字符串作为视图名,Model直接写在Handler方法的形参上
Cookie
不能直接放在形参中,可以通过request获得cookie
@RequestMapping("cookie") public BaseRespVo cookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { System.out.println("cookie:" + cookie.getName() + " → " + cookie.getValue()); } return BaseRespVo.ok(); }
通过浏览器构造cookie
20211231154858979.png&pos_id=img-XwiWAXIf-1706540147877)
postman构造cookie
Session
session也可以通过request来获得;另外session可以直接写在形参中 → HttpSession
//localhost:8080/other/session/put?username=songge @RequestMapping("session/put") public BaseRespVo put(HttpServletRequest request,String username) { HttpSession session = request.getSession(); session.setAttribute("username", username); return BaseRespVo.ok(); } //localhost:8080/other/session/get @RequestMapping("session/get") public BaseRespVo get(HttpSession session) { Object username = session.getAttribute("username"); return BaseRespVo.ok(username); }
RESTful
表述性状态传递Representational State Transfer
使用Json数据做交互,更侧重于响应
建议大家请求URL:资源(名词)+操作(动词)
/user/query
/user/insert
/user/update
/user/delete
注解:获得值给到Handler方法的形参,这些值是和请求相关的
即使用注解完成相关的编程流程
请求URL→ @PathVariable
localhost:8080/article/details?username=xxx&id=xxx
提供占位符,一个占位符在article之前,一个占位符在details之后;占位符写{xxx},xxx是占位符的名称
这样就可以根据传入的参数来动态的生成url,类似于vue中的插值表达式,{}中的内容是和注解对应的属性绑定的
//localhost:8080/article/details //提供占位符,一个占位符在article之前,一个占位符在details之后;占位符写{xxx},xxx是占位符的名称 //使用的是@PathVariable注解的value属性来获得对应占位符的值 @RequestMapping("{aaa}/article/details/{bbb}") public BaseRespVo articleDetails(@PathVariable("aaa")String username, @PathVariable("bbb")Integer id) { return BaseRespVo.ok(username + ":" + id); }
根据userid做用户信息的查询的url → /user/query/5
@RequestMapping("query/{id}") public BaseRespVo queryUser(@PathVariable("id") Integer id){ User user = userMapper.selectUserById(id); return BaseRespVo.ok(user); }
请求参数 → @RequestParam
无用
//@RequestParam注解的value属性和形参名对应起来,形参就可以接收到对应的值 // 同时会限定要携带对应的请求参数 //而这个过程我们直接让形参名和请求参数名一致就可以做到 //localhost:8080/user/login?username=songge&password=niupi @RequestMapping("user/login") public BaseRespVo login(@RequestParam("username") String usernamex, @RequestParam("password") String passwordy) { return BaseRespVo.ok(); }
请求头 → @RequestHeader
获得指定请求头的值
指定的冒号左边的部分,获得是冒号右边的部分
//可以通过String或String[]来接收对应的值 //如果以数组来接收,其实就是将字符串根据逗号作为分隔符转换数组 @RequestMapping("header") public BaseRespVo header(@RequestHeader("Accept")String[] accept, @RequestHeader("Host") String host) { //String usernamesString = "songge,ligenli,xuejia"; //String[] split = usernamesString.split(","); return BaseRespVo.ok(); }
注解value属性的值需要与请求头对应
Cookie → @CookieValue
如果要获得指定name所对应的value,你要拿到所有的Cookie去遍历
可以通过注解直接拿到指定name所对应的value
@RequestMapping("cookie/value") public BaseRespVo cookieValue(@CookieValue("songge")String value) { return BaseRespVo.ok(value); }
Session → @SessionAttribute
直接拿到指定attributeName对应的value
//放入的时候放入的是什么类型,接收的时候就是什么类型 //简化的是session.getAttribute @RequestMapping("session/get") public BaseRespVo sessionGet(@SessionAttribute("username")String username) { return BaseRespVo.ok(username); }
静态资源处理
在整合了MVC之后,web资源路径下的静态资源就无法正常访问了
原因:静态资源本应该由default的Servlet来处理,但在SpringMVC中都会交给DispatcherServlet来处理,由于没有写对应的处理静态资源的Servlet,就会造成访问不到的情况
解决的办法:
- 配置default servlet
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping>
- 使用DispatcherServlet给出的默认配置
x <mvc:default-servlet-handler
- 以上两种方式只能访问到web资源根路径下的静态资源,不能访问其他地方的,有局限性
- 静态资源映射
<!--ResourceHandler的配置--> <!--mapping属性:映射的url--> <!--location属性:文件所处的真实路径--> <!--访问静态资源的请求URL:分为了两部分,mapping的属性值 + 静态资源相对于location的位置--> <mvc:resources mapping="/pic/**" location="/"/><!--web资源根路径--> <mvc:resources mapping="/pic2/**" location="classpath:/def/"/><!--classpath路径--> <mvc:resources mapping="/pic3/**" location="file:D:/spring/"/><!--文件路径,建议大家使用的路径--> <!--注意事项:location最后位置是/-->
前面的/pic类似于替代后面location中的目录,接下来只需要写相对于location目录下的资源路径即可
示意图
上传并访问
使用配置文件来管理文件相对路径,便于管理
<context:property-placeholder location="classpath:param.properties"/>
加载上传的驱动,使用配置文件配置路径映射
<mvc:resources mapping="/pic4/**" location="file:${file.path}"/><!--文件路径,建议大家使用的路径--> <!--注意事项:location最后位置是/--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
编写上传servlet
@RestController @RequestMapping("upload") public class uploadController { @Value("${file.path}") String path; @RequestMapping("file") public BaseRespVo upload(MultipartFile file) throws IOException { file.transferTo(new File(path,file.getOriginalFilename())); return BaseRespVo.ok(); } }
异常处理
向上抛出异常,可以通过异常处理器进行统一的异常处理,也提供了个性化的处理,个性化的处理是根据异常的类型做个性化。
HandlerExceptionResolver
对异常进行统一的处理
接口,接口中提供了resolveException方法
范围:全部类型
如何生效:只需要注册到容器中就生效了
如果要做个性化的处理需要你自己来写业务
返回值:ModelAndView
如果需要返回Json,就需要调用response
public interface HandlerExceptionResolver { /** * var3: handler * var4: 抛出的异常 */ @Nullable ModelAndView resolveException(HttpServletRequest var1, HttpServletResponse var2, @Nullable Object var3, Exception var4); }
@Component public class CustomHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("/exception.jsp"); if (e instanceof ArithmeticException){ modelAndView.setViewName("/arithmetic.jsp"); } return modelAndView; } }
***@ExceptionHandler
注解,注解的value属性Class<? extends Throwable>[],写的是异常类的Class
范围:value属性中的异常类型
如何生效:ElementType.method,方法要处于ControllerAdvice组件中
返回值:ModelAndView、Json
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExceptionHandler { Class<? extends Throwable>[] value() default {}; }
ModelAndView
直接返回String就是视图名
//@ExceptionHandler(value = {ArithmeticException.class}) /*@ExceptionHandler(ArithmeticException.class) public ModelAndView arithmetic() { ModelAndView modelAndView = new ModelAndView("/arithmetic.jsp"); return modelAndView; }*/ @ExceptionHandler(ArithmeticException.class) public String arithmetic(){
Json
增加@ResponseBody注解
@ExceptionHandler(ArithmeticException.class) @ResponseBody public BaseRespVo arithmetic() { return BaseRespVo.fail("算术异常3.0"); }
@ResponseBody可以写在类上,意味着该类下所有的方法响应都是Json
引申注解:@RestControllerAdvice = @ResponseBody + @ControllerAdvice
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @ControllerAdvice @ResponseBody public @interface RestControllerAdvice {}
//@ControllerAdvice //@ResponseBody @RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(ArithmeticException.class) //@ResponseBody public BaseRespVo arithmetic() { return BaseRespVo.fail("算术异常3.0"); } }
可以将异常写在形参中,获取抛出异常的对象
@ExceptionHandler(ArithmeticException.class) //@ResponseBody public BaseRespVo arithmetic(ArithmeticException exception) { //return BaseRespVo.fail("算术异常3.0"); return BaseRespVo.fail(exception.getMessage());//by zero }
写业务时,可以自定义异常,通过抛出自定义的异常,做对应的异常处理,就可以响应对应的json数据
拦截器
filter
主要是解决Post请求乱码的问题
配置自带的CharacterEncodingFilter
它的作用就是判断forceRequestEncoding和forceResponseEncoding是否为true,如果为true则设置字符集为encoding对应的值
配置的过程
<!--Filter配置 class、映射范围--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--使用其set方法,用到了init-param标签--> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> <!--<init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param>--> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <!--全部请求都来设置字符集--> <url-pattern>/*</url-pattern> </filter-mapping>
HandlerInterceptor
是一个拦截器接口,其中提供了3个方法
public interface HandlerInterceptor { /** * 返回值为boolean:返回值决定是否继续执行 * handler:HandlerMethod */ default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } /** * 是在Handler方法执行之后 * ModelAndView 获得Handler方法的执行结果 * 响应给用户之前 */ default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } /** * 处理结果之后 * ex:可以获得Handler方法抛出的异常,即使抛出异常,也可以为true * 如果当前的preHandle执行到了,并且呢结果为true,则一定可以执行到对应的afterCompletion */ default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
HandlerInterceptor和Handler之间的关系是什么样子?
通过HandlerExecutionChain(链)来维护的,并且Handler和chain之间是一对一的关系
public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final Object handler; @Nullable private HandlerInterceptor[] interceptors; @Nullable private List<HandlerInterceptor> interceptorList; }
HandlerExcutionChain如何来的 → doDispatch → getHandler → 是通过HandlerMapping来获得的
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { Iterator var2 = this.handlerMappings.iterator(); while(var2.hasNext()) { HandlerMapping mapping = (HandlerMapping)var2.next(); HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
获得HandlerExecutionChain,接下来做了啥事情
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = this.getHandler(processedRequest); //执行到了HandlerExecutionChain的applyPreHandle,如果返回值为false,则结束这个流程 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 执行的是Handler方法 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 在Handler方法执行之后执行的 → 并且第三个参数传入的Handler方法的执行结果mv mappedHandler.applyPostHandle(processedRequest, response, mv); //处理最终结果 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); finally{ mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } }
如果applyPreHandle返回值为false,则结束这个流程,我们来看下它做了什么
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { //获得该Handler对应的多个HandlerInterceptor HandlerInterceptor[] interceptors = this.getInterceptors(); //非空判断,如果为空,则直接return true if (!ObjectUtils.isEmpty(interceptors)) { // interceptors不为空,则遍历,i++ → 正序的遍历 → 给interceptorIndex赋值 for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) { // 获得当前正在遍历的HandlerInterceptor HandlerInterceptor interceptor = interceptors[i]; //如果HandlerInterceptor的preHandle为false,则满足判断条件 if (!interceptor.preHandle(request, response, this.handler)) { //如果preHandle返回值为false → 这里return了false //→ 导致了applyPreHandle返回值为false this.triggerAfterCompletion(request, response, (Exception)null); //意味着HandlerInterceptors中只要有一个Interceptor的preHandle为false //则中断doDispatch //我们又发现在中断doDispatch之前,执行了第14行代码 → 执行的afterCompletion return false; } } } return true; }
在结束之前执行到了14行this.triggerAfterCompletion(request, response, (Exception)null);
执行的是对应的afterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { //先去获得HandlerInterceptors HandlerInterceptor[] interceptors = this.getInterceptors(); //做了非空判断 if (!ObjectUtils.isEmpty(interceptors)) { //执行遍历 //从interceptorIndex开始执行的,执行到哪一个HandlerInterceptor的preHandle // --i 倒序 for(int i = this.interceptorIndex; i >= 0; --i) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable var8) { logger.error("HandlerInterceptor.afterCompletion threw exception", var8); } } } }
如果有5个HandlerInterceptor,如果第4个preHandle为false,执行情况是什么样子的
preHandle1234、afterCompletion321
如果applyPreHandle所有的HandlerInterceptor的preHandle都返回true,则继续流程
执行applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = this.getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { //非空判断,--i 倒序遍历,遍历的是全部的HandlerInterceptor的postHandle for(int i = interceptors.length - 1; i >= 0; --i) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } }
注意:一旦preHandle为false则一个postHandle也执行不到。所有的preHandle都为true,则会执行所有的postHandle
后面的流程接着保证afterCompletion的执行
完整的执行流程
1.通过执行doDispatch中的getHandler方法,在其中通过HandlerMapping建立映射关系并执行getHandler方法获得了HandlerExecutionChain,Handler和Chain之间是一对一的关系,在Chain中维护了一个interceptor的list,所以handler和interceptor是一对多的关系。
2.执行HandlerExecutionChain的applyPreHandle方法,如果返回值是false的话则结束这个流程,在这个方法中遍历了interceptor数组,并执行每一个interceptor的preHandle方法,如果这个preHandle方法的返回值是fasle那么最终就会导致applyPreHandle的返回值是false,这样就会终止整个流程,也就是说如果遍历的数组中只要有一个的preHandle方法的返回值是false,那么就会中断doDispatch的流程。这里在中断之前,执行了triggerAfterCompletion方法,这里会根据interceptorIndex进行倒序的遍历,这个Index就是执行到的数组中的interceptor的个数,如果此时执行到第五个返回了false,那么就会执行4321个AfterCompletion方法,因为只有返回值是true才能保证AfterCompletion一定执行,如果返回false那么当前的就不会执行。
3.如果applyPreHandle所有的HandlerInterceptor的preHandle都返回true,则继续流程,执行applyPostHandle,执行全部Interceptor的postHandle方法,这里也是倒序执行。这里要注意只有所有的preHandle返回true才会执行到这里
4.最后有各种手段来执行AfterCompletion方法
如果要使用HandlerInterceptor我们需要做什么?
- HandlerInterceptor是谁
- HandlerInterceptor的作用范围
- 直接写bean标签或ref标签:全局
- mvc:interceptor标签:局部
- HandlerInterceptor的顺序
- 书写顺序
首先定义一个类来实现接口,实现自己需要的方法即可
@Component public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object username = session.getAttribute("username"); if (username==null){ return false; } return true; } }
然后在配置文件中配置
<mvc:interceptors> <!--bean标签和ref标签配置HandlerInterceptor时,其实指定了作用范围:全局--> <!--注意:这个全局是DispatcherServlet作用范围下的全局--> <!--bean标签意味着局部组件--> <!--<bean class="com.cskaoyan.interceptor.CustomHandlerInterceptor"/>--> <!--ref标签意味着引用组件的id--> <!--<ref bean="customHandlerInterceptor"/>--> <!--也可以指定局部范围--> <mvc:interceptor> <!--指定作用范围 **代表多级url--> <mvc:mapping path="/hello/**"/> <!--bean标签或ref标签指定HandlerInterceptor--> <ref bean="customHandlerInterceptor"/> </mvc:interceptor> <ref bean="customHandlerInterceptor2"/> <ref bean="customHandlerInterceptor3"/> </mvc:interceptors>
执行的顺序就是注册组件的顺序
HibernateValidation
校验框架,请求参数的合法性校验
以JavaBean来接收请求参数。请求参数名和JavaBean的成员变量名是对应起来,对请求参数做校验,转移到对成员变量做校验。
通过注解来建立关系 ,如果不同的校验逻辑提供了不同的注解,就是对成员变量(请求参数)增加不同的功能的校验注解,就意味着增加了校验功能
引入依赖
hibernate-validator使用6版本的
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.0.Final</version> </dependency>
注册组件
validator
LocalValidatorFactoryBean,但是它是虚假的FactoryBean,没有实现FactoryBean接口
<mvc:annotation-driven validator="validator"/> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> </bean>
使用注解
参数校验声明@Valid或@Validated
//localhost:8080/user/register2?username=songge&password=niupi&age=30 @RequestMapping("register2") public BaseRespVo register2(@Validated User user) { return BaseRespVo.ok(); }
校验功能注解
@Data public class User { @Length(min = 6) String username; @Length(min = 6,max = 10) String password; @Max(100) @Min(18) Integer age; }
常见的注解 (Bean Validation 中内置的 constraint)
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期 Date
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
没有通过校验的警告信
http://localhost:8080/user/register2?username=songge&password=niupile&age=120
Field error in object ‘user’ on field ‘age’: rejected value [120]; codes [Max.user.age,Max.age,Max.java.lang.Integer,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],100]; default message [最大不能超过100]]
自行处理校验结果
//在形参中增加一个BindingResult //localhost:8080/user/register3?username=songge&password=niupi&age=30 @RequestMapping("register3") public BaseRespVo register3(@Validated User user, BindingResult bindingResult) { //如何知道校验没有通过 if (bindingResult.hasFieldErrors()) {//只要有一个成员变量没有通过校验,返回true //如果校验没有通过是谁导致的 → 获得校验错误 FieldError fieldError = bindingResult.getFieldError(); //校验没有通过我们能获得哪些信息 String field = fieldError.getField();//获得成员变量名 → 请求参数名 Object rejectedValue = fieldError.getRejectedValue();//导致校验失败的值 String defaultMessage = fieldError.getDefaultMessage(); String msg = "请求参数" + field + "没有通过校验:" + rejectedValue + "; " + defaultMessage; return BaseRespVo.fail(msg); } return BaseRespVo.ok(); }
这里要注意,如果获取bindingResult的同时又要使用Session,那么要将bindingResult写在前面,否则会出现问题
修改默认的消息
校验功能注解的属性中,message属性
@Length(min = 6,max = 10,message = "length between 6 and 10") String password;
JavaConfig
使用Java代码和注解完成对应的配置
application.xml → 配置类
***MVC配置类
@ComponentScan(“com.cskaoyan”) → context:component-scan
@EnableWebMvc → mvc:annotation-driven
SpringMVC这里我们做过哪些配置
- mvc:resources
- mvc:interceptors
- mvc:annotation-driven conversion-service
- mvc:annotation-driven validator
- multipartResolver
WebMvcConfigurer接口提供了这些方法 → 配置类实现这个接口
@ComponentScan("com.cskaoyan") @EnableWebMvc public class MvcConfiguration implements WebMvcConfigurer { }
mvc:resources静态资源映射
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //静态资源映射mapping location registry.addResourceHandler("/pic1/**").addResourceLocations("/"); registry.addResourceHandler("/pic2/**").addResourceLocations("classpath:/"); registry.addResourceHandler("/pic3/**").addResourceLocations("file:d:/spring/"); }
mvc:interceptors HandlerInterceptor配置
@Override public void addInterceptors(InterceptorRegistry registry) { //HandlerInterceptor是谁、作用范围是什么、顺序 registry.addInterceptor(new CustomHandlerInterceptor());//作用范围是全局 registry.addInterceptor(new CustomHandlerInterceptor2()).addPathPatterns("/hello/**"); registry.addInterceptor(new CustomHandlerInterceptor3()).addPathPatterns("/goodbye/**"); }
类型转换服务
取出、增加、放回
@Autowired ConfigurableConversionService conversionService; //利用生命周期 → 来执行方法 @PostConstruct public void addCustomConverter() { conversionService.addConverter(new String2DateConverter()); } @Bean @Primary public ConfigurableConversionService conversionService() { return conversionService; }
简单的方式
//添加Converter可以使用addFormatters @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new String2DateConverter()); }
校验器
mvc:annotation-driven validator
@Override public Validator getValidator() { LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); validator.setProviderClass(HibernateValidator.class); return validator; }
文件上传的处理器
//要么通过方法名指定组件id,要么通过@Bean的value属性指定;组件id是固定值 @Bean public MultipartResolver multipartResolver() { return new CommonsMultipartResolver(); }
web.xml → 配置类
AACDSI
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { //spring的配置文件 return new Class[]{SpringConfiguration.class}; } @Override protected Class<?>[] getServletConfigClasses() { //mvc配置文件 return new Class[]{MvcConfiguration.class}; } @Override protected String[] getServletMappings() { //dispatchServlet作用范围 return new String[]{"/"}; } }
Spring配置类
//额外扫描到SpringMVC的配置类和Controller组件 //Filter里的type可以不写,默认值就是FilterType.ANNOTATION @ComponentScan(value = "com.cskaoyan", excludeFilters = {@ComponentScan.Filter(/*type = FilterType.ANNOTATION,*/ value = {Controller.class, EnableWebMvc.class})}) @Configuration public class SpringConfiguration { }
SpringMVC的配置类中可以使用Spring配置类中的组件
取出、增加、放回
@Autowired ConfigurableConversionService conversionService; //利用生命周期 → 来执行方法 @PostConstruct public void addCustomConverter() { conversionService.addConverter(new String2DateConverter()); } @Bean @Primary public ConfigurableConversionService conversionService() { return conversionService; }
简单的方式
//添加Converter可以使用addFormatters @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new String2DateConverter()); }
校验器
mvc:annotation-driven validator
@Override public Validator getValidator() { LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); validator.setProviderClass(HibernateValidator.class); return validator; }
文件上传的处理器
//要么通过方法名指定组件id,要么通过@Bean的value属性指定;组件id是固定值 @Bean public MultipartResolver multipartResolver() { return new CommonsMultipartResolver(); }
web.xml → 配置类
AACDSI
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { //spring的配置文件 return new Class[]{SpringConfiguration.class}; } @Override protected Class<?>[] getServletConfigClasses() { //mvc配置文件 return new Class[]{MvcConfiguration.class}; } @Override protected String[] getServletMappings() { //dispatchServlet作用范围 return new String[]{"/"}; } }
Spring配置类
//额外扫描到SpringMVC的配置类和Controller组件 //Filter里的type可以不写,默认值就是FilterType.ANNOTATION @ComponentScan(value = "com.cskaoyan", excludeFilters = {@ComponentScan.Filter(/*type = FilterType.ANNOTATION,*/ value = {Controller.class, EnableWebMvc.class})}) @Configuration public class SpringConfiguration { }
SpringMVC的配置类中可以使用Spring配置类中的组件