SpringBoot默认把类路径下的/static、/resources、/public、/META-INF/resources文件夹映射为/**,可以通过addResourceHandlers来自定义映射路径。
以下例子更具不同系统环境添加不同的路径,映射地址为/imgs/**。也可以根据@Value注解拿到配置文件中的值。
@Configuration
public class WebMvnConfig extends WebMvcConfigurationSupport {
@Value("${application.static.res-path}")
private String resPath;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
String path = System.getProperty("os.name").equalsIgnoreCase("linux") ? "file:/home/imgs/" : "file:E:/imgs/";
registry.addResourceHandler("/imgs/**").addResourceLocations(path);
}
}
通过addInterceptors可以添加拦截器,拦截器需要实现HandlerInterceptor接口,并在preHandle中处理逻辑,返回true则不拦截,否则拦截,拦截器也可以对静态资源拦截。
addPathPatterns用于添加拦截的路径,通过一个可变参数接收,excludePathPatterns用于排除路径。
如下代码,对/admin/下除了login不拦截,其余都拦截。并且拦截/imgs/下除了2.jpg,其余都拦截。
在preHandle中简单判断了请求参数user是否为听风逝夜并且pass为abc123,否则拦截,这时候应该跳转到其他界面。
@Configuration
public class WebMvnConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle------------->"+request.getRequestURL());
/**
* 逻辑处理
*/
/**
* 返回true则不拦截,false则拦截
*/
boolean result = request.getParameter("user")
.equals("听风逝夜") && request.getParameter("pass").equals("abc123");
if (!result){
response.sendRedirect("/admin/login");
}
return result;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//在Controller处理完之后回调,preHandle返回false则不走这里
System.out.println("postHandle------------>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//整个请求处理完毕回调方法,preHandle返回false则不走这里
System.out.println("afterCompletion-------------->");
}
}).addPathPatterns("/admin/**","/imgs/**").excludePathPatterns("/imgs/2.jpg","/admin/login");
}
}
不过这方法和@CrossOrigin感觉都有坑,还是用过滤器解决跨域问题吧。
@Override
protected void addCorsMappings(CorsRegistry registry) {
super.addCorsMappings(registry);
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.allowCredentials(true)
.allowedHeaders("*")
.maxAge(3600);
}
访问一个页面时在Controller中也许会这样做
@GetMapping("/")
public String index(){
return "index";
}
但是这里面没什么逻辑,不能每个都这样写吧,所以可以使用addViewControllers来解决
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/").setViewName("/index");
}
以上两个方法相等。
如果想实现自定义参数解析,如把以下格式的日期解析到LocalDateTime中,可以在resolveArgument中添加一个HandlerMethodArgumentResolver解决。
首先定义一个注解。
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Date {
String value();
boolean required() default true;
}
其次添加一个HandlerMethodArgumentResolver实现类,在supportsParameter中判断是否需要转换,也就是看看参数上是否有我们自定义的注解。如果返回true,则进入resolveArgument方法,进行转换,返回值将被SpringBoot设置到原来参数上。如果返回的类型和原来参数上的不一致,将报错。
以下例子判断参数上是否有自定义的Date注解,存在则进入resolveArgument方法,首先获取注解中的value值,然后通过NativeWebRequest获取url中的对应值,如果为null或者split后大小不为5,则返回null,否则转换成LocalDateTime类型并返回。
@Configuration
public class WebMvnConfig extends WebMvcConfigurationSupport {
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(Date.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
Date date =methodParameter.getParameterAnnotation(Date.class);
String parameter = nativeWebRequest.getParameter(date.value());
if (parameter!=null){
String[] split = parameter.split(",");
if (split.length==5){
return LocalDateTime.of(converInteger(split[0]),converInteger(split[1]),converInteger(split[2]),converInteger(split[3]),converInteger(split[4]));
}
}
return null;
}
});
}
private Integer converInteger(String param){
return Integer.valueOf(param);
}
}
接着就可以在方法中使用,在参数上加上@Date注解,就可以接收date=2020,2,18,8,8这种格式日期数据
@GetMapping("/")
public String index(@Date("date") LocalDateTime date){
System.out.println("index"+date);
return "index";
}
通过@ResponseBody可以把对象转换成json返回,于是你想这样做,有一个注解,标记在Controller方法上,则会返回这个对象的xml格式数据。实现方法就可以在addReturnValueHandlers中添加一个HandlerMethodReturnValueHandler。
首先编写一个注解,标明返回值是xml类型。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseXmlBody {
}
其次,在HandlerMethodReturnValueHandler的supportsReturnType方法中判断方法上是否有ResponseXmlBody注解,为true则进入handleReturnValue。
handleReturnValue中的o参数则是Controller方法的返回值,通过反射一系列操作后,拼接成一个xml格式的数据,并使用nativeWebRequest获取到输出流,设置Content-Type为text/plain;charset=utf-8,但是这里一定要设置modelAndViewContainer.setRequestHandled(true);。
@Configuration
public class WebMvnConfig extends WebMvcConfigurationSupport {
@Override
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
super.addReturnValueHandlers(returnValueHandlers);
returnValueHandlers.add(new HandlerMethodReturnValueHandler() {
@Override
public boolean supportsReturnType(MethodParameter methodParameter) {
return methodParameter.hasMethodAnnotation(ResponseXmlBody.class);
}
@Override
public void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception {
modelAndViewContainer.setRequestHandled(true);
HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
response.addHeader("Content-Type", "text/plain;charset=utf-8");
Class<?> aClass = o.getClass();
StringBuffer value =new StringBuffer();
Field[] declaredFields = aClass.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
declaredFields[i].setAccessible(true);
addNode(value,declaredFields[i].getName(),declaredFields[i].get(o));
}
StringBuffer rootStringBuffer =new StringBuffer();
addNode(rootStringBuffer,aClass.getSimpleName(),value);
response.getWriter().append(rootStringBuffer);
}
});
}
private void addNode(StringBuffer stringBuffer,String name,Object value){
stringBuffer.append("<");
stringBuffer.append(name);
stringBuffer.append(">");
stringBuffer.append(value);
stringBuffer.append("<");
stringBuffer.append(name);
stringBuffer.append(">");
stringBuffer.append("\n");
}
}
最终输出如下。上面代码不能更生层次解析对象,想要完整的话自己实现或者使用框架哦。
比如使用@RequestParam接收Book对象,url中格式是:?book=书名,价格 这样的,@RequestParam无法直接转换,可以通过addFormatters自定义格式化来解决。
parse方法中的String s则是url中的对应参数。
@Configuration
public class WebMvnConfig extends WebMvcConfigurationSupport {
@Override
protected void addFormatters(FormatterRegistry registry) {
super.addFormatters(registry);
registry.addFormatter(new Formatter<Book>() {
@Override
public Book parse(String s, Locale locale) throws ParseException {
String[] split = s.split(",");
if (split.length==2){
return new Book(split[0],Float.valueOf(split[1]));
}
return null;
}
@Override
public String print(Book book, Locale locale) {
return null;
}
});
}
}
public class Book {
public Book() {
}
public Book(String bookName, Float price) {
this.bookName = bookName;
this.price = price;
}
private String bookName;
private Float price;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
}
@GetMapping("addBook")
@ResponseBody
public Object date(@RequestParam("book")Book book){
System.out.println(book);
return book;
}