- 对部分接口做使用说明
- 实现 public String user(@UserInfo String userName) 可获取用户信息
获取用户信息实现流程
- CurrentUserMethodArgumentResolver
- UserInfo
- AppMvcConfig.addArgumentResolvers
- TestController.user(@UserInfo String userName)
拦截器执行顺序
- HandlerInterceptor.preHadnle
- TestController.test
- ResponseBodyAdvice.supports
- ResponseBodyAdvice.beforeBodyWrite
- HandlerInterceptor.postHandle
- HandlerInterceptor.afterCompletion
代码如下 :
- TestController.java : 测试controller
- AppMvcConfig.java : 配置文件
- MvcClient.java : 测试类
- MyHandlerExceptionResolver.java : 异常处理
- MyHandlerInterceptor.java : HandlerInterceptor
- MyResponseBodyAdvice.java : ResponseBodyAdvice
- MyWebApplicationInitializer.java : springmvc项目启动类
- CurrentUserMethodArgumentResolver.java : 用户信息
- UserInfo.java : 注解类
TestController
package com.web.controller;
import com.web.user.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* 测试controller
*/
@Controller
public class TestController {
@GetMapping("/test")
@ResponseBody
public String test() {
System.err.println(" TestController.test ");
return "hello world!";
}
@GetMapping("/map")
@ResponseBody
public Map<String, Object> map() {
Map<String, Object> map = new HashMap<>();
map.put("name", "anyf");
return map;
}
@GetMapping("/user")
@ResponseBody
public String user(@UserInfo String userName) {
System.err.println(" TestController.user = " + userName);
return userName;
}
}
AppMvcConfig
package com.web;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.web.user.CurrentUserMethodArgumentResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* 配置文件
*/
@ComponentScan("com.web")
@EnableWebMvc
public class AppMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
/**
* 添加 HandlerInterceptor
*/
registry.addInterceptor(new MyHandlerInterceptor());
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
/**
* 添加 HandlerMethodArgumentResolver,拦截添加了@UserInfo注解的controller,并对用户信息赋值
*/
resolvers.add(myHandlerMethodArgumentResolver());
}
@Bean
public CurrentUserMethodArgumentResolver myHandlerMethodArgumentResolver() {
return new CurrentUserMethodArgumentResolver();
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
/**
* 解决 : org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class java.util.HashMap
* 返回map报错
*/
converters.add(0, fastJsonHttpMessageConverter());
converters.add(1, responseBodyStringConverter());
}
@Bean
public HttpMessageConverter<String> responseBodyStringConverter() {
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
}
@Bean
public HttpMessageConverter<?> fastJsonHttpMessageConverter() {
return new FastJsonHttpMessageConverter();
}
}
MvcClient
package com.web;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import javax.servlet.ServletException;
/**
* 测试代码
* 解决 : java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet
* gradle 增加 : optional("org.apache.tomcat.embed:tomcat-embed-jasper:8.0.50")
*
* http://localhost:8080/app/test
*
*/
public class MvcClient {
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir(".");
tomcat.setPort(8080);
/**
* 说明是web项目
*/
tomcat.addWebapp("/app", "D:\\Program Files\\logs\\");
tomcat.start();
tomcat.getServer().await();
}
}
MyHandlerExceptionResolver
package com.web;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* HandlerExceptionResolver : 异常处理
* HandlerExceptionResolver接口中定义了一个resolveException方法,用于处理Controller中的异常。
* Exception ex参数即Controller抛出的异常。返回值类型是ModelAndView,可以通过这个返回值来设置异常时显示的页面。
*/
@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
String requestType = request.getHeader("X-Requested-With");
String contentType = request.getContentType() == null ? "" : request.getContentType().toLowerCase();
String message;
if (ex instanceof GeneralException) {
// 用户自定义异常
message = ((GeneralException) ex).getSimpleMessage();
} else { // 通用异常
message = "系统异常!";
}
// 判断是否是Ajax 请求
if (contentType.contains("application/json") || !StringUtils.isEmpty(requestType) && ("XMLHttpRequest".equalsIgnoreCase(requestType))) {
Assert.notNull(response);
response.setContentType("text/json;charset=utf-8");
ModelAndView modelAndView = new ModelAndView();
// 返回异常信息(JSON)
try {
PrintWriter writer = response.getWriter();
writer.write(message);
writer.flush();
} catch (IOException ignore) {
} finally {
modelAndView.clear();
return modelAndView;
}
} else {
// 页面跳转
Map<String, Object> modal = new HashMap<>();
modal.put("exceptionMessage", message);
modal.put("ex", ex);
return new ModelAndView("error/error", modal);
}
}
}
class GeneralException extends Exception{
public String getSimpleMessage() {
return getMessage();
}
}
MyHandlerInterceptor
package com.web;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* HandlerInterceptor
*/
public class MyHandlerInterceptor implements HandlerInterceptor {
/**
* 在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.err.println(" HandlerInterceptor.preHadnle ");
return true;
}
/**
* 在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView;
*
* 对于@ResponseBody和ResponseEntity方法,postHandle不太有用,因为它们的响应是在handleAdapter内和postHandle之前写入和提交的。
* 这意味着对响应进行任何更改都为时已晚,例如添加额外的头。
* 对于这样的场景,您可以实现ResponseBodyAdvice并将其声明为控制器通知bean,或者直接在RequestMappingHandlerAdapter上配置它。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.err.println(" HandlerInterceptor.postHandle ");
}
/**
* 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.err.println(" HandlerInterceptor.afterCompletion ");
}
}
MyResponseBodyAdvice
package com.web;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* ResponseBodyAdvice
*/
@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
System.err.println(" ResponseBodyAdvice.supports ");
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
System.err.println(" ResponseBodyAdvice.beforeBodyWrite " + body);
return body;
}
}
MyWebApplicationInitializer
package com.web;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
/**
* springmvc项目启动类
* 利用了servlet3.0特性,替代web.xml配置文件
* 启动web服务后,会调用 onStartup
*/
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
System.err.println("=============onStartUp=============");
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppMvcConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
CurrentUserMethodArgumentResolver
package com.web.user;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* HandlerMethodArgumentResolver,用户信息
*/
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 判断参数是否添加了@UserInfo注解
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UserInfo.class);
}
/**
* 获取用户信息,并将用户信息进行赋值
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
/**
* 可以改为从request获取数据,或者从redis获取数据
*/
return "anyf";
}
}
UserInfo
package com.web.user;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserInfo {
}
spring-ayf-test.gradle
plugins {
id 'java'
}
group 'org.springframework'
version '5.1.9.RELEASE'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile(project(":spring-context"))
compile(project(":spring-web"))
compile(project(":spring-webmvc"))
optional("javax.servlet:javax.servlet-api:3.1.0")
optional("org.apache.tomcat.embed:tomcat-embed-core:8.0.50")
optional("org.apache.tomcat.embed:tomcat-embed-jasper:8.0.50")
optional("com.alibaba:fastjson:1.2.75")
testCompile group: 'junit', name: 'junit', version: '4.12'
}