05-SpringMVC

nobility 发布于 2022-03-29 2441 次阅读


SpringMVC

Spring5.x要求tomcat版本至少是为8.5,一般使用Maven引入spring-webmvc就会将Web模块引入,切记将javax包排除,也就是将Tomcat中有的包排除

在引入IOC和AOP模块的基础上在引入Web模块

基本使用

web.xml中配置SpringMVC提供的前端控制器DispatcherServlet

<servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>  <!--配置Spring全局配置文件的位置,当该类被加载时会自动创建IOC容器-->
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </init-param>
  <load-on-startup>0</load-on-startup>  <!--让SpringIOC容器预加载-->
</servlet>
<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>  <!--让Spring的前端控制器拦截所有请求-->
</servlet-mapping>

<!--
Tomcat默认有一个servlet是用于处理静态资源的,默认是匹配路径 / ,所以优先级最低,
也可以覆盖此配置达到排除静态资源的目的
-->
<!--<servlet-mapping>-->
<!--  <servlet-name>default</servlet-name>-->
<!--  <url-pattern>/static/*</url-pattern>-->
<!--</servlet-mapping>-->

再在Spring全局配置文件applicationContext.xml中添加下面配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">
  <!--
  首先添加 xmlns:mvc="http://www.springframework.org/schema/mvc" 约束文件
  再在 xsi:schemaLocation属性后增加 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
  之后使用下面标签才能有代码提示
  -->
  <context:component-scan base-package="com"/>  <!--开启IOC注解扫描-->
  <mvc:annotation-driven/>  <!--开启SpringMVC注解开发模式-->
  <mvc:default-servlet-handler/>  <!--在使用DispatcherServlet前端控制器拦截时,将静态资源排除在外-->
  <!-- <mvc:resources mapping="/static/**" location="/static/"/> -->
  <!--resources标签也可以指定静态资源,以/static路径开头的,可访问/webapp/static目录-->
</beans>

在类中使用注解,具体如下

package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller  //交由spring容器管理该类对象
public class Main {
  @RequestMapping(value = "/test", method = RequestMethod.GET)  //定义请求映射,若不指定请求方法则任意请求都可以
  @ResponseBody  //该方法的返回值直接返回
  public String test() {
    return "Hello world";
  }
}

URL映射

package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/prefix")  //通常RequestMapping作用于类上,用于定义请求路径前缀
public class Main {
  @GetMapping("/get")  //get请求
  @ResponseBody
  public String get() {
    return "get method";
  }

  @PostMapping("/post")  //post请求
  @ResponseBody
  public String post() {
    return "post method";
  }

  @PutMapping("/put")  //put请求
  @ResponseBody
  public String put() {
    return "put method";
  }

  @DeleteMapping("/delete")  //delete请求
  @ResponseBody
  public String delete() {
    return "delete method";
  }
}

请求参数

当有多个请求参数时,使用键值对都是String类型的Map进行接收,即可自动将其封装成Map对象

queryString请求参数

作用与Get请求,当请求参数与方法参数数据类型不一样时,SpringMVC会自动转化,数据类型校验应该在前端进行,否则可能会出现类型转化异常的400客户端错误

简单参数
  • 请求参数与方法的参数一一对应即可
  • 若该参数有多个值,可使用List集合进行接收
  • 若请求参数与方法参数不能一一对应时,可使用@RequestParam注解进行对应,若此参数不是必须的,就将该注解的required设置为fasle
package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Main {
  @GetMapping("/test1")
  @ResponseBody
  public String test1(Integer id) {  //请求参数与方法参数一一对应,数据类型自动转化
    return "id: " + id;
  }

  @GetMapping("/test2")
  @ResponseBody
  public String test2(@RequestParam("abc") String id) {
    //使用@RequestParam注解手动对应,默认是必须参数,未传入参数时会报错
    return "abc: " + id;
  }

  @GetMapping("/test3")
  @ResponseBody
  public String test3(@RequestParam(value = "abc", required = false) String id) {
    //使用@RequestParam注解手动对应,可设置非必须参数,未传入参数时该参数值为null,
    return "abc: " + id;
  }
}

使用下面JSP页面进行测试

<a href="${pageContext.request.contextPath}/test1?id=1">/test1?id=1</a><br>
<a href="${pageContext.request.contextPath}/test2?abc=1">/test2?abc=1</a><br>
<a href="${pageContext.request.contextPath}/test3">/test3</a><br>
对象参数
  • 对于方法参数是复杂类型时,请求参数与对象属性一一对应即可,对象属性还是对象时支持级联方式进行对应(强制要求,无法使用@RequestParam注解)
  • 若方法参数既有复杂数据类型又有简单数据类型,并且还有冲突的情况下,SpringMVC会同时注入两个值
  • 该对象也可以是Map数据结构,会依次解析成Map中的键值对
package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

class Student {
  private String id;
  private String name;
  //setter getter toString 省略
}

@Controller
public class Main {

  @GetMapping("/test1")
  @ResponseBody
  public String test1(Student student) {  //请求参数与对象属性一一对应
    return "student: " + student;
  }

  @GetMapping("/test2")
  @ResponseBody
  public String test2(Student student, String id) {  //冲突情况下,同时注入两个值
    return "student: " + student + " | id: " + id;
  }
}

使用下面JSP页面进行测试

<a href="${pageContext.request.contextPath}/test3?id=1&name=zs">/test3?id=1&amp;name=zs</a><br>
<a href="${pageContext.request.contextPath}/test4?id=1&name=zs">/test4?id=1&amp;name=zs</a>

path请求参数

@Controller
  public class Main {  
    @GetMapping("/test/{id}")  //使用花括号包裹路径请求参数
    @ResponseBody
    public String test(@PathVariable("id") Integer id) {  //使用@PathVariable注解对应路径请求参数
      return "id: " + id;
    }
}

使用下面JSP页面进行测试

<a href="${pageContext.request.contextPath}/test/1">/test/1</a>

queryBody请求参数

请使用至少2.9.x版本,因为之前的版本与MySQL同时使用时存在很严重的安全隐患

作用与Post请求,为了将JSON数据转化为Java对象,首先需要引入JSON序列化包jackson-databind,之后不需要任何配置,因为Spring全局配置文件中配置过<mvc:annotation-driven/>注解开发模式,由SpringMVC自动创建该类中的转换器对象(该包转换器类实现了HttpMessageConverter接口,转化返回值类型),所以就会自动转化

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>x.x.x</version>
</dependency>

参数上使用@RequestBody注解,该组件会自动将JSON格式字符串序列化成Java对象

package work.nobility.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Map;

class User {
    private Integer id;
    //setter getter toString 省略
}
@Controller
public class Main {
    @PostMapping("/test1")
    @ResponseBody
    public String test1(@RequestBody User user) {
        return user.toString();
    }
    @PostMapping("/test2")
    @ResponseBody
    public String test2(@RequestBody Map<String,Object> map) {
        return map.toString();
    }
}

Http请求元信息

@Controller
public class Main {
  @GetMapping("/test1")
  @ResponseBody
  public String test(@RequestHeader("User-Agent") String userAgent) {  //使用@RequestHeader注解获取对应请求头信息
    return "userAgent: " + userAgent;
  }
  
  @GetMapping("/test2")
  @ResponseBody
  public String test(@CookieValue("Idea-efd34b6e") Cookie cookie) {  //使用@CookieValue注解对应路Cookie对象,这里使用的是开发工具自带的Cookie
    return "cookie: " + cookie.getValue();
  }
}

使用下面JSP页面进行测试

<a href="${pageContext.request.contextPath}/test1">/test1</a><br>
<a href="${pageContext.request.contextPath}/test2">/test2</a>

使用ServletAPI

若是Maven项目,需要引入javax.servlet-api包,注意要将依赖范围设置为provided,因为这些类型参数是该包中的类

在方法的参数列表中定义HttpServletRequestHttpServletResponseHttpSession类型的参数,SpringMVC会根据类型自动注入这些参数,直接使用即可

对于请求转发可使用@RequestAttribute注解快速获取

@Controller
public class Main {
  @GetMapping("/test1")
  @ResponseBody
  public String test(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    System.out.println(request);
    System.out.println(response);
    System.out.println(session);
    return "hello world";
  }

  @GetMapping("/test2")
  public String test2(HttpServletRequest request) {
    request.setAttribute("message", "hello world");  //设置请求参数
    return "/test3";  //未加@ResponseBody注解,会进行请求转发到test3地址上
  }

  @GetMapping("/test3")
  @ResponseBody
  public String test3(@RequestAttribute("message") String message) {
    return "test3: " + message;
  }
}

响应结果

我所探测到的,支持返回String、ModeAndView、void,ResponseEntity和普通对象类型,若返回其他类型抛出异常,若非要返回其他类型数据可能就需要手写解析器了,比如JSON解析器

返回String类型

  • 使用@ResponseBody注解,表示该方法直接产生响应体数据,不经过视图,用于生成JSON等结构化字符串
  • 类上使用@RestController注解代替@Controller注解,表示该类下的所有方法都会直接返回字符串
  • 若不使用@ResponseBody@RestController注解,直接返回的字符串会被当成请求转发的视图页面
package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@Controller
//@RestController
public class Main {
  @GetMapping("/test1")
  @ResponseBody
  public String test1(Integer id) {
    return "id: " + id;
  }

  @GetMapping("/test2")
  public String test2(HttpServletRequest request) {
    request.setAttribute("id", 1);
    return "/index.jsp";  //请求转发到index.jsp
  }

  @GetMapping("/test3")
  public String test3() {
    return "redirect:/index.jsp";  //使用 redirect: 前缀表示重定向
  }
}

使用下面jsp页面进行测试

<a href="${pageContext.request.contextPath}/test1?id=1">/test1?id=1</a><br>
<a href="${pageContext.request.contextPath}/test2">/test2</a><br>
<a href="${pageContext.request.contextPath}/test3?id=1">/test3?id=1</a><br>
<h2>id: ${requestScope.id}</h2>

返回ModelAndView类型

  • 方法返回ModelAndView对象,可向视图中绑定数据,ModelAndView是SpringMVC提供的一个类
package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Main {

  @GetMapping("/test1")
  public ModelAndView test1(Integer id) {
    ModelAndView modelAndView = new ModelAndView("/index.jsp");  //若视图不使用斜杠开头表示使用该类的路径前缀做前缀
    //modelAndView.setViewName("/view.jsp");  //也可使用该方法修改视图
    modelAndView.addObject("id", id);  //默认将属性加入到请求对象上
    return modelAndView;  //返回ModelAndView对象,默认是请求转发方式
  }

  @GetMapping("/test2")
  public ModelAndView test2(Integer id) {
    ModelAndView modelAndView = new ModelAndView("redirect:/index.jsp");  //使用 redirect: 表示重定向
    modelAndView.addObject("id", id);  //重定向,由于是新的请求,所以该数据无法传递到视图
    return modelAndView;
  }
}

使用下面jsp页面进行测试

<a href="${pageContext.request.contextPath}/test1?id=1">/test1?id=1</a><br>
<a href="${pageContext.request.contextPath}/test2?id=1">/test2?id=1</a><br>
<h2>id: ${requestScope.id}</h2>

返回普通对象类型

请使用至少2.9.x版本,因为之前的版本与MySQL同时使用时存在很严重的安全隐患

默认调用对象的toString()方法,为了返回JSON数据,首先需要引入JSON序列化包jackson-databind,之后不需要任何配置,因为Spring全局配置文件中配置过<mvc:annotation-driven/>注解开发模式,由SpringMVC自动创建该类中的转换器对象(该包转换器类实现了HttpMessageConverter接口,转化返回值类型),所以就会自动转化

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>x.x.x</version>
</dependency>

在控制器上类中使用@ResponseBody@RestController注解,并且方法中返回对象时(List集合会转化成JavaScript数组),该组件会自动序列化成JSON格式字符串

下面是简单使用,默认情况下对于时间类型返回的是时间戳,若不想返回时间戳可使用@JsonFormat注解进行格式化(同时设置时区),该注解也可以格式化数字

package com;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

class Student {
  private Integer id;
  private String name;
  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8")
  private Date birthday;
  //setter getter toString 省略
}

@Controller
public class Main {
  @GetMapping("/test")
  @ResponseBody
  public Student test() {
    Student student = new Student();
    student.setId(1);
    student.setName("zs");
    student.setBirthday(new Date());
    return student;
  }
}

返回void类型

使用Servlet中的请求响应对象手动转发

package com;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class Main {
  @GetMapping("/test1")
  public void test1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setAttribute("id", 1);
    request.getRequestDispatcher("/index.jsp").forward(request, response);
  }

  @GetMapping("/test2")
  public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException {
    request.setAttribute("id", 1);
    response.sendRedirect(request.getContextPath() + "/index.jsp");
  }
}

使用下面jsp页面进行测试

<a href="${pageContext.request.contextPath}/test1">/test1</a><br>
<a href="${pageContext.request.contextPath}/test2">/test2</a><br>
<h2>id: ${requestScope.id}</h2>

返回ResponseEntity类型

用于自定义HTTP响应

package com;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class Main {
  @GetMapping("/test")
  public ResponseEntity<String> get() {  //泛型指定返回类型,泛型也是普通对象,与直接返回普通对象一致
    HttpHeaders headers = new HttpHeaders();  //创建响应头
    headers.setContentType(MediaType.APPLICATION_JSON);  //指定媒体类型
    HttpStatus status = HttpStatus.resolve(200);  //创建响应状态码
    return ResponseEntity  //返回响应对象
        .status(status)  //指定http响应状态码
        .headers(headers)  //指定http响应头
        .body("请求体");   //指定http响应体,对应ResponseEntity的泛型
  }
}

异常处理器

在异常处理器类上使用@ControllerAdvice注解,异常处理器方法上使用@ExceptionHandler注解指定要处理的异常,之后在控制器中抛出异常时,异常处理器中匹配的方法就会执行

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class MyException {
  @ExceptionHandler(value = {Exception.class})  //数组形式,可指定多个异常
  @ResponseBody
  public String error(Exception e) {  //与控制器中的方法用法一致
    return "出现异常" + e.getMessage();
  }
}

拦截器

若是Maven项目,需要引入javax.servlet-api包,注意要将依赖范围设置为provided,因为拦截器中的参数需要用到该包中的类

自定义类实现HandlerInterceptor接口,重写preHandle()postHandle()afterCompletion()方法,这三个方法都是默认方法

  • preHandle():前置执行处理,进入控制器之前执行,若返回false则后续不会执行
  • postHandle():目标资源已被SpringMVC进行处理,即控制器方法被执行完(return了之后)后执行
  • afterCompletion():响应文本已产生,即响应HTML字符串或JSON字符串生成后执行

同时设置多个拦截器的执行顺序为,请求时按照配置顺序进行执行,响应时按照配置逆序执行,若期间某个拦截器出现了异常,则后续拦截器不会被执行,而是直接逆序执行afterCompletion()方法,而不会执行postHandle()方法

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("前置处理");
    return true;  //返回true后续会接着执行
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println("控制器方法执行完毕");
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("响应文本已经生成");
  }
}

之后再在Spring全局配置文件applicationContext.xml中添加下面配置,但是要注意<mvc:default-servlet-handler/>设置对拦截器是不起作用的,静态资源还是会被拦截器拦截到

<mvc:interceptors>  <!--设置SpringMVC拦截器,-->
  <mvc:interceptor>  <!--设置单个拦截器,可设置多个拦截器-->
    <mvc:mapping path="/**"/>  <!--拦截的路径,可是设置多个-->
    <mvc:exclude-mapping path="/**.jsp"/>  <!--不拦截的路径,可是设置多个-->
    <bean class="com.MyInterceptor"/>  <!--拦截器类-->
  </mvc:interceptor>
</mvc:interceptors>

使用下面代码进行测试

public class Main {
  @GetMapping("/test")
  @ResponseBody
  public String test() {
    System.out.println("控制器中的方法");
    return "test";
  }
}

SpringMVC处理流程

SpringMVC处理流程

解决常见问题

格式转化器

局部日期格式转化
@Controller
public class Main {
  @GetMapping("/test")
  @ResponseBody
  public String test(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") Date date) {
    return "date: " + date;
  }
}
//用于测试的连接
//<a href="${pageContext.request.contextPath}/test?date=1970-01-01 00:00:00.000">/test?date=1970-01-01 00:00:00.000</a>
全局日期格式转化

自定义格式转化器,实现Converter接口,重写convert()方法,优先级低于局部日期转化,这只是个示例,自定义转换器可用于任意类型的转化

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateConverter implements Converter<String, Date> {  //实现Converter接口,泛型表示将String转化为Date类型
  @Override
  public Date convert(String string) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    try {
      return simpleDateFormat.parse(string);  //返回转化后的日期对象
    } catch (ParseException e) {
      return null;  //解析错误返回null
    }
  }
}

再在Spring全局配置文件applicationContext.xml中更新下面配置

<context:component-scan base-package="com"/>
<mvc:annotation-driven conversion-service="FormattingConversionServiceFactoryBean"/>  <!--指定转换器工厂,之后遇到转换器能转化的就会使用转换器转化-->
<mvc:default-servlet-handler/>

<bean id="FormattingConversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  <!--创建转换器工厂-->
  <property name="converters">  <!--注入自定义转化器-->
    <set>
      <bean class="com.DateConverter"/>
    </set>
  </property>
</bean>

解决中文乱码

请求中的中文乱码

对于Get请求,Tomcat8及以上版本Get请求参数默认就是UTF-8,Tomcat7需要在Tomcat的server.xml配置文件中找到这项配置:<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />,添加一个属性字段URLEncoding="UTF-8",改为这样<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URLEncoding="UTF-8" />即可

对于Post请求,需要在web.xml中配置SpringMVC提供的字符编码过滤器即可,具体如下

<filter>
  <filter-name>characterEncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>  <!--配置字符编码为UTF-8-->
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>characterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>  <!--拦截所有请求-->
</filter-mapping>
响应中的中问乱码
局部解决

在URL映射注解中设置produces属性,可指定Context-Text的值,以@RequestMapping注解为例,因为可添加到类上

@RequestMapping(produces = "text/html;charset=utf-8")
全局解决

在Spring全局配置文件applicationContext.xml中更新下面配置

<context:component-scan base-package="com"/>
<mvc:annotation-driven>  <!--开启此标签的双标签模式-->
  <mvc:message-converters>
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">  <!--指定消息转换器-->
      <property name="supportedMediaTypes">   <!--注入支持的媒体类型-->
        <list>
          <value>text/html;charset=utf-8</value>  <!--html类型-->
          <value>application/json;charset=utf-8</value>  <!--json类型-->
        </list>
      </property>
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven> 
<mvc:default-servlet-handler/>

解决非简单请求接收不到参数问题

需要在web.xml中配置SpringMVC提供的表单内容过滤器即可,具体如下

<filter>
  <filter-name>formContentFilter</filter-name>
  <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>formContentFilter</filter-name>
  <url-pattern>/*</url-pattern>   <!--拦截所有请求-->
</filter-mapping>

解决跨域请求

局部注解方式

在控制器类上使用@CrossOrigin注解,表示该类下的所有映射的URL都支持跨域请求,具体使用如下

@CrossOrigin(origins = {"http://www.baidu.com"})  //origins是一个数组,可指定多个域名
//@CrossOrigin(origins = "*")  //也可使用星号通配符进行全部放行
//@CrossOrigin(origins = {"http://www.baidu.com"},maxAge = 3600)  //maxAge属性表示缓存预检请求缓存时间,可减请服务器的压力,单位秒
@RestController
public class Main {
  //...
}
全局xml方式

在Spring全局配置文件applicationContext.xml中添加下面配置

  <mvc:cors>
    <mvc:mapping path="/prefix/**" allowed-origins="http://www.baidu.com" max-age="3600"/>
    <!--path属性决定了哪些请求路径可以跨域访问,/prefix/** 代表 prefix 父路径下的所有路径-->
     <!--allowed-origins中多个域名使用逗号分隔即可-->
  </mvc:cors>

整合Freemarker

引入freemarker包和spring-context-support整合包

在Spring全局配置文件applicationContext.xml中添加下面配置

<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <property name="contentType" value="text/html;charset=utf-8"/>  <!--设置contentType-->
  <property name="suffix" value=".ftl"/>  <!--指定FreeMarker模板文件的后缀名,在程序中就可省略后缀名-->
</bean>
<bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="/WEB-INF/ftl"/>  <!--指定模板文件目录,若代码中不想使用该目录,添加 forward: 前缀即可-->
  <property name="freemarkerSettings">
    <props>
      <prop key="defaultEncoding">UTF-8</prop>  <!--指定Freemarker脚本与数据渲染时使用的字符集-->
    </props>
  </property>
</bean>

使用下面代码测试

@Controller
public class Main {
  @GetMapping("/test")
  public ModelAndView test(Integer id) {
    ModelAndView modelAndView = new ModelAndView("/index");
    //无需添加后缀,以为已经配置过,并且 / 根对应模板文件根目录
    modelAndView.addObject("id", id);
    return modelAndView;
    ///index.ftl中内容为:<h1>${id}</h1>
  }
}
此作者没有提供个人介绍
最后更新于 2022-03-29