@Controller
将Java类标记为控制器类,方便扫描添加到IOC容器中。
@RequestMapping
@RequestMapping的作用将请求和处理请求的控制器建立一个映射关系。
标记在类上: 定义同意路径规则,相当于组。
标记在方法上: 定义具体映射规则,唯一路径。
String[] value: 指定请求路径,如果只有一个参数可以默认不写,能够匹配多个请求。
String[] method: 接收请求类型,可以设置种或多种请求方式,默认是全部请求都处理。
["RequestMethod.GET","RequestMethod.POST","RequestMethod.PUT","RequestMethod.DELETE"]
[@GetMapping, @PostMapping, @PutMapping, @DeleteMapping]
String[] params: "username=root" 请求必须携带username参数并且username等于root。
通过Headers控制请求头,限制只有firefox浏览器才能访问此资源
String[] headers: "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0"
Spring MVC支持Ant风格:
1.value="/a?a/ant": ? 表示匹配任意单个字符
2.value="/a*a/ant": * 表示匹配零个或多个字符
3.value="/a**a/ant": ** 表示匹配一级或多级目录
Spring MVC支持Restful风格: 参数占位符
value="/rest/{id}" 接收参数: @PathVariable("id") Integer id
原生 Servlet API
//原生Servlet API获取参数
HttpServletRequest request
String[] ops = request.getParameterValues("op");
for (String op : ops) {
System.out.println(op);
}
控制器形参获取参数
处理器形参中的参数名要与实参参数名保持一致。
如果接收多个同名参数就使用数组 String[] op。
参数重命名,非必须传入参数,参数默认值为root。
@RequestParam(value = "username",required = false,defaultValue = "root") String user_name
获取请求头信息
@RequestHeader(value = "Host",required = false,defaultValue = "localhost:8080") String host
获取Cookie值
@CookieValue(value = "JSESSIONID",required = false,defaultValue = "mycookie") String cookie
如果参数为一个实体对象,则可以直接用实体类作为形参接收
视图模型ModelAndView
@RequestMapping(value = "/request")
public ModelAndView request() {
//创建视图模型
ModelAndView modelAndView = new ModelAndView();
//处理模型数据,向请求域request共享数据
modelAndView.addObject("framework","Spring Cloud");
//添加Map集合 addAllObjects(Map<String,?>)
//设置视图名称
modelAndView.setViewName("request");
return modelAndView;
}
//Model,ModelMap,Map之间的关系
最终实现都是BindingAwareModelMap类,类依赖关系如下
BindingAwareModelMap extends ExtendedModelMap,
ExtendedModelMap extends ModelMap implements Model,
ModelMap extends LinkedHashMap<String, Object>
//封装视图模型
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
域对象处理
1.在方法参数添加HttpSession session即可使用原生API。
2.ServletContext application = session.getServletContext(); //application域处理
网络资源视图
"forward:/resourcePath" //转发
"redirect:/resourcePath" //重定向
RestFul风格
GET:资源获取 POST:资源创建 PUT:资源更新 DELETE:资源删除
报文信息转换器
HttpMessageConverter
@RequestBody 封装参数
@ResponseBody 回写数据
RequestEntity 封装完整请求参数[包括请求头等]
ResponseEntity 静态类,可以设置完整响应信息[包括响应头等]
文件上传下载
<!-- 文件上传依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- CommonsMultipartResolver规则配置 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<!-- 1024 * 1024 * 20 = 20M -->
<property name="maxUploadSize" value="20971520"></property>
<property name="maxInMemorySize" value="20971520"></property>
</bean>
<!-- 前端文件上传下载格式 -->
<a th:href="@{/fileDown}">文件下载</a><br/>
<form th:action="@{/fileUp}" method="post" enctype="multipart/form-data">
上传文件<input type="file" name="photo"/><br/>
<input type="submit" value="上传"/>
</form>
@RequestMapping(value = "/fileDown")
public ResponseEntity<byte[]> json(HttpSession session) {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中资源真实路径
String realPath = servletContext.getRealPath("/static/bin/DMS.exe");
//文件流处理
FileInputStream in = null;
ResponseEntity<byte[]> responseEntity = null;
try {
in = new FileInputStream(realPath);
byte[] bs = new byte[in.available()];
in.read(bs);
//创建HttpHeaders对象
MultiValueMap<String,String> headers = new HttpHeaders();
//设置下载方式及其文件名称
headers.add("Content-Disposition","attachment;filename=MSD.exe");
//响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
responseEntity = new ResponseEntity<>(bs,headers,statusCode);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return responseEntity;
}
@ResponseBody
@RequestMapping(value = "/fileUp")
public String fileUp(MultipartFile photo,HttpSession session) {
//获取服务资源路径
String realPath = session.getServletContext().getRealPath("/static/jar/");
File file = new File(realPath);
if (!file.exists()){
System.err.println(realPath);
file.mkdir();//创建目录
}
//获取文件名
String originalFilename = photo.getOriginalFilename();
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
String uuid = UUID.randomUUID().toString();
String uuidFile = uuid+suffixName;
//File.separator:文件分隔符
String fileName = realPath+File.separator+uuidFile;
try {
photo.transferTo(new File(fileName));
return "success";
} catch (IOException e) {
return "fail";
}
}
Spring MVC 拦截器
Filter是基于函数回调的,而Interceptor则是基于Java反射的,
拦截器主要作用于拦截控制器的方法,过滤器作用于Servlet容器。
在action的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。
执行流程: 过滤前-拦截前-action执行-拦截后-过滤后
多拦截器:
1.先配置的拦截器bean先触发执行。
2.拦截器1pre-拦截器2pre-action执行-拦截器2post-拦截器1post-拦截器2after-拦截器1after。
<!-- 文件上传解析器,将上传的文件封装为MultipartFile -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<!-- 配置拦截器[默认拦截所有请求] -->
<bean id="testInterceptor" class="com.example.interceptors.TestInterceptor"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/testInterceptor"/>
<ref bean="testInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
public class TestInterceptor implements HandlerInterceptor {
//任务执行前处理
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.err.println("任务执行前处理");
return true;//true放行下一步执行
}
//任务执行后处理
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.err.println("任务执行后处理");
}
//视图渲染后处理
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.err.println("视图渲染后处理");
}
}
异常处理器
处理控制器执行过程中所发生的异常。
<!-- 配置异常处理映射解析器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!-- 捕获异常共享到Request域中 -->
<property name="exceptionAttribute" value="ex"/>
</bean>
@ControllerAdvice
public class TestExceptionHandler {
//vaue为数组类型,可以定义多种异常类型
@ExceptionHandler(value = {ArithmeticException.class})
public String testExceptionHandler(Exception ex, Model model) {
model.addAttribute("ex", ex);
return "error";
}
}
Spring MVC - Ajax跨域问题
Ajax工程
//webpack工程
import $ from 'jquery';
$(function() {
$("#btn").click(function() {
$.ajax({
type: 'get',
url: 'http://localhost:8080/emp',
contentType: "application/json;charset=UTF-8",
dataType: 'json',
success: function(data) {
console.log(data);
}
});
});
});
局部跨域
/**
* origins:允许可访问的域列表
* maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
*/
@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
public class AjaxController {
@GetMapping(value = "/emp")
public Employee emp() {
return new Employee(1,"特朗普",74,'男');
}
}
全局跨域
//全局跨域
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
Spring MVC 注解驱动开发
Config
//Web工程的初始化类
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
//指定Spring配置
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//指定Spring MVC配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMVCConfig.class};
}
//配置url映射路径
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//过滤器规则配置
@Override
protected Filter[] getServletFilters() {
//设置字符编码过滤器
CharacterEncodingFilter encoding = new CharacterEncodingFilter();
encoding.setEncoding("UTF-8");
encoding.setForceResponseEncoding(true);
//设置隐藏方法过滤器
HiddenHttpMethodFilter hiddenMethod = new HiddenHttpMethodFilter();
return new Filter[]{encoding, hiddenMethod};
}
}
@EnableWebMvc//开启MVC注解驱动
@Configuration//表示为Spring配置类
@ComponentScan(basePackages = "com.example.controller")//扫描控制器
public class WebMVCConfig implements WebMvcConfigurer {
//配置生成模板解析器
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
// ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
assert webApplicationContext != null;
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
Objects.requireNonNull(webApplicationContext.getServletContext()));
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
//生成模板引擎并为模板引擎注入模板解析器
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
//生成视图解析器并未解析器注入模板引擎
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
//视图控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("hello");
}
//静态资源处理
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//文件上传解析器
@Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
//拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor())
.addPathPatterns("/hello");//添加拦截规则
}
//异常处理器
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver exceptionResolver =
new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException","error");
exceptionResolver.setExceptionMappings(prop);
exceptionResolver.setExceptionAttribute("ex");
resolvers.add(exceptionResolver);
}
}
@Configuration
public class SpringConfig {
}
Interceptor
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse
response,
Object handler) throws Exception {
System.err.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.err.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.err.println("afterCompletion");
}
}
Controller
@Controller
public class TestController {
@RequestMapping("/")
public String index() {
return "index";
}
@RequestMapping("/test")
public void test() {
System.out.println(4/0);
}
}
Spring MVC 执行流程
1.Http请求发送到Tomcat服务器,先通过Servlet容器,执行Filter和Service方法。
2.请求到达DispatcherServlet,将请求转发到HandlerMapping,查找url映射的控制器。
3.将查找到的控制器和拦截器信息封装成一个执行链返回给DispatcherServlet。
4.先执行控制器前置拦截器,然后执行控制器适配器,最后执行控制器。
5.成功执行控制器后得到ModelAndView视图模型并返回,然后执行控制器后置拦截器。
6.DispatcherServlet接收到ModelAndView后交给视图解析器执行解析视图。
7.视图解析器解析出视图后返回给DispatcherServlet进行视图渲染,渲染完成后执行渲染后拦截器,响应用户。