目录
MVC
javaBean分类
MVC工作流程
SpringMVC
SpringMVC的特点
SpringMVC的基本组件
SpringMVC执行流程
SpringMVC的使用
@RequestMapping注解
@RequestMapping注解标识的位置
@RequestMapping注解属性
SpringMVC支持ant风格的路径
restful风格
使用方法
占位符方式获取参数值
用实体类形参获取请求参数
SpringMVC获取请求参数
通过servletAPI获取
通过控制器方法形参注解获取参数
@RequestParam注解
@RequestHeader注解
@CookieValue注解
利用pojo获取请求参数
同名参数提交问题
对象封装
restful形式
解决获取请求参数的乱码问题
域对象共享数据
使用servletAPI向request域对象中共享数据
使用ModelAndView向request域中共享对象
使用model向请求域中共享数据
使用modelmap向请求域中共享数据
使用Map向请求域中共享数据
向session域中共享数据
向application域中共享数据
SpringMVC的视图
ThymeleafView
转发视图(internalResourceView)
重定向视图(RdirectView)
视图控制器
用表单发送put或delete请求
配置默认servlet处理静态资源
@RequestBody注解
使用过程
用实体类进行封装
用map集合进行封装
@ResponseBody注解
使用步骤
@RestController注解
SpringMVC实现下载功能
SpringMVC实现上传功能
拦截器
使用过程
多个拦截器的执行顺序
异常处理器
xml文件内配置异常处理
使用注解配置异常处理
注解配置SpringMVC
含义:MVC是一种架构思想,将软件按照模型、视图、控制器来划分
用户通过视图层发起请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕后将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。
含义:SpringMVC是spring为表述层开发提供的一套完备的解决方案
注意:三层架构分为表述层(表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
用户发起请求到前端控制器,前端控制器捕获请求并对url进行解析,得到请求资源标识符,判断请求uri对应的映射,若映射不存在则看是否配置默认servlet处理器,没配置或找不到资源则报404,配置了并且找到资源则访问目标,根据该uri调用处理器映射器获得该handler配置的所有相关对象(包括Handler对象以及handler对象对应的拦截器),最后以HandlerExecutionChain执行链的对象形式返回给处理器控制器,处理器控制器根据获得的Handler选择一个合适的处理器适配器开始执行拦截器或方法;执行完毕后返回ModelAndView给前端控制器;前端控制器根据返回的ModelAndView选择一个合适的ViewResolver进行视图解析,根据Model和View来渲染视图,之后将渲染的结果返回给客户端。
org.springframework
spring-webmvc
5.3.1
ch.qos.logback
logback-classic
1.2.3
javax.servlet
javax.servlet-api
3.1.0
org.thymeleaf
thymeleaf-spring5
3.0.12.RELEASE
SpringMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
1
SpringMVC
/
//请求控制器
@Controller
public class HelloController {
@RequestMapping("/")
public String protal(){
//将逻辑视图返回
return "success";
}
}
注意:这里返回页面名称即可,因为页面前缀与页面后缀已经在springmvc配置文件中设置
总结:浏览器发送请求,若请求地址符合前端控制器url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取springmvc的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中的@requestMapping注解的value值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应的页面
前言:从注解名字上我们可以看出,@RequestMapping注解的作用就是将请求和处理请求的控制器方法进行关联,建立起映射联系;当springmvc接收到这个请求,那么就会来找到在映射关系中对应的控制器方法来处理这个请求。
value属性:value属性值是一个String类型数组形式,表示可以根据多个路径来匹配对应的方法
method属性:该属性类型是RequestMethod[],也为一个数组;表示当前控制器方法所允许接受的请求类型
注意:由于日常只使用支持单个请求的方法,所以在@RequestMapping注解的基础上结合请求方式诞生出一堆派生注解(@GetMapping、@PostMapping、@DeleteMapping、@PutMapping)
params属性:该属性类型为String[],其作用为通过请求参数匹配请求,即浏览器发送的请求参数必须满足以下设置
- "param":表示当前匹配的请求的请求参数中必须携带特定的param参数
- "!param":表示当前匹配的请求的请求参数中一定不能携带param参数
- "param=value":表示当前匹配的请求请求参数中必须携带param参数,并且值必须为value
- "param!=value":表示当前匹配的请求请求参数中可以不携带param参数,若携带,则值一定不为value
headers属性:其类型为String[],其作用是通过请求报文匹配请求,即浏览器的请求头必须满足如下设置
- "key":要求映射匹配的请求头必须包含key请求头信息
- "!key":要求映射匹配的请求头不能包含key请求头信息
- "key=value":要求请求映射所匹配的请求必须携带key请求头信息,并且值为value
- “key!=value":要求请求映射所匹配的请求可以不携带key请求头,若携带则值不为value
注意:请求头和响应头的键不区分大小写
路径中的占位符(在@RequestMapping的value属性内)
rest(representational state transfer):表现层资源状态转移
restful风格提倡url地址使用统一的风格设计,从前到后各个单词使用/分开,不使用问号键值对等方式携带请求参数,而是将要发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。
需要在@RequestMapping注解的value属性中所设置的路径中,使用{xxx}的方式表示路径中的数据,在通过@PathVariable注解,将占位符所表示的值和控制器方法的形参进行绑定
注意:此种方式对于post请求或get请求都适用
@Controller
@RequestMapping("/test")
public class ProtalController {
@RequestMapping(value= "/get/{username}/{password}")
public String getParam(@PathVariable("username") String username,@PathVariable("password") Integer password){
System.out.println("名字为:"+username+",密码为:"+password);
return "success";
}
}
请求路径:http://localhost:8080/springmvc/test/get/lili/123
注意:
@RequestMapping("/pojo/{username}/{password}")
public String getParamByPojo(User user){
System.out.println(user);
return "success";
}
public class User {
private Integer id;
private String username;
private String password;
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
请求路径:http://localhost:8080/springmvc/pojo/lili/123
注意:
@Controller
public class TestParam {
@RequestMapping("/servletAPI")
public String getParams(HttpServletRequest httpServletRequest){
//对于这种获取参数方式get或post均可
String username = httpServletRequest.getParameter("username");
String password = httpServletRequest.getParameter("password");
System.out.println("名字为:"+username+",密码为:"+password);
return "success";
}
}
请求路径:http://localhost:8080/springmvc/servletAPI?username=lili&password=123
@RequestMapping("/param")
public String getParam(@RequestParam(value = "username",required = false,defaultValue = "lili") String u,@RequestParam("password") Integer p){
//get或post请求参数都可以获取
System.out.println("名字为:"+u+",密码为:"+p);
return "success";
}
请求路径:http://localhost:8080/springmvc/param?username=lili&password=234
注意:
作用:将请求头信息与请求方法的形参进行绑定(里面的值添请求头的key)
@RequestMapping("/param")
public String getParam(@RequestHeader("accept") String accept){
System.out.println(accept);
return "success";
}
注意:这里可以得到请求头的accept的值,该注解的使用方法和@RequestParam使用方法类似
作用:将cookie信息与请求方法的形参进行绑定(里面的值添cookie的key)
public class User {
private Integer id;
private String username;
private String password;
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
@RequestMapping("/pojo")
public String getParamByPojo(User user){
System.out.println(user);
return "success";
}
注意:
请求路径:http://localhost:8080/springmvc/pojo?username=lili&password=123
总结:需要在控制器方法的形参位置设置实体类的形参,要保证实体类中的属性的属性名和请求参数的名字一致,就可以通过实体类的形参获取请求参数(实体类必须有set该属性的方法)
public class User {
private String[] hobbys;
public void setHobbys(String[] hobbys) {
this.hobbys = hobbys;
}
@Override
public String toString() {
return "User{" +
"hobbys=" + Arrays.toString(hobbys) +
'}';
}
}
@RequestMapping("/like")
public String getParams(User user){
System.out.println(user);
return "success";
}
请求路径:http://localhost:8080/springmvc/like?hobbys=足球,篮球
@RequestMapping("/like/{hobbys}")
public String getParams(@PathVariable("hobbys") String[] hobbys){
System.out.println(Arrays.toString(hobbys));
return "success";
}
请求路径:http://localhost:8080/springmvc/like/足球,篮球
其他类型都差不多,不多写了
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/*
注意:SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
@RequestMapping("/request")
public String haveAll(HttpServletRequest request){
request.setAttribute("message", 23);
Object message = request.getAttribute("message");
System.out.println(message);
return "success";
}
访问路径:http://localhost:8080/springmvc/request
注意:
@RequestMapping("/request")
public ModelAndView haveAll(String username){
//ModelAndView包含model和view的功能
ModelAndView modelAndView = new ModelAndView();
//向请求域中共享数据
modelAndView.addObject("message",88);
//获取数据
Map model = modelAndView.getModel();
Object message = model.get("message");
System.out.println(message);
//设置逻辑视图
modelAndView.setViewName("success");
System.out.println(username);
//使用ModelAndView那么返回值必须为ModelAndView
return modelAndView;
}
请求路径:http://localhost:8080/springmvc/request?username=lili
@RequestMapping("/model")
public String testModel(Model model){
model.addAttribute("message", "hello world");
Object message = model.getAttribute("message");
System.out.println(message);
return "success";
}
@RequestMapping("/modelMap")
public String testModel(ModelMap modelMap){
modelMap.addAttribute("message","我是信息");
Object message = modelMap.getAttribute("message");
System.out.println(message);
return "success";
}
@RequestMapping("/map")
public String testMap(Map map){
map.put("message", 67);
Object message = map.get("message");
System.out.println(message);
return "success";
}
@RequestMapping("/session")
public String testSession(HttpSession session){
session.setAttribute("message", "hello");
Object message = session.getAttribute("message");
System.out.println(message);
return "success";
}
@RequestMapping("/application")
public String testApplication(HttpSession session){
//最大域对象
ServletContext servletContext = session.getServletContext();
servletContext.setAttribute("message", 67);
Object message = servletContext.getAttribute("message");
System.out.println(message);
return "success";
}
前言:springmvc中的视图是view接口,视图的作用是渲染数据,将模型model中的数据展示给用户
springmvc视图的种类很多,默认有转发视图和重定向视图
注意:当工程引入jstl依赖时,转发视图会自动转换为jstlView
当控制器方法中所设置的视图名称没有任何前缀时,此时视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转。
@RequestMapping("/thymeleaf")
public String testThymeleafView(){
return "success";
}
配置视图解析器
注意:在SpringMVC的配置文件中配置了该视图解析器,由此视图解析器解析之后所得到的视图为ThymeleafView
@RequestMapping("/thymeleaf")
public String testThymeleafView(String username){
System.out.println(username+"2");
System.out.println("转发视图成功");
return "success";
}
@RequestMapping("/forward")
public String testForward(String username){
System.out.println(username+"1");
return "forward:/thymeleaf";
}
请求路径:http://localhost:8080/springmvc/forward?username=lili
注意:转发视图也可以实现请求的转发,但不能实现视图的渲染,渲染还需要thymeleaf
@RequestMapping("/thymeleaf")
public String testThymeleafView(String username,Integer password){
System.out.println(username+password);
return "success";
}
@RequestMapping("/redirect")
public String testRedirect(Integer password){
return "redirect:http://localhost:8080/springmvc/thymeleaf?username=lili"+"&password="+password;
}
请求路径:http://localhost:8080/springmvc/redirect?password=234
注意:如果我们写的路径是绝对路径,那么在重定向实现页面跳转的时候,他会自动的在我们设置的绝对路径前面加上上下文路径的
在springmvc配置文件中配置
注意:设置完视图控制器标签后,那么当前请求只有视图控制器的请求被前端控制器处理,其他的请求全部404;若要解决问题,则必须开启mvc注解驱动
注意:浏览器目前只能发送get或post请求,若要发送put或delete请求,需要在web.xml中配置一个过滤器,配置了过滤器之后,发送的请求要满足两个条件才能将请求方式转换为put或delete
HiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
HiddenHttpMethodFilter
/*
注意:配置默认servlet处理静态资源标签的同时也应该开启mvc注解驱动,两个标签一起配置作用:当前的请求先由前端控制器处理,若处理不了,则由默认的servlet(tomcat)来处理
作用:将请求体中的内容与控制器方法的形参进行绑定(将json格式数据转换为java对象)
com.fasterxml.jackson.core
jackson-databind
2.13.3
axios.post("/mvc_axios/test2",{username:"admin",password:456,age:18,gender:"女"})
.then(res=>{console.log(res.data)})
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String gender;
}
@RequestMapping("/test2")
public void testJson(@RequestBody User user, HttpServletResponse response) throws Exception {
System.out.println(user);
response.getWriter().write("hello"+user);
}
@RequestMapping("/test2")
public void testMap(@RequestBody Map map, HttpServletResponse response) throws Exception {
System.out.println(map);
response.getWriter().write("hello"+map);
}
作用:将所标识的控制器方法的返回值作为响应报文的响应体相应到浏览器(响应json格式数据)
注意:@ResponseBody可以放在类上或方法上,若放在类上则所有的方法的返回值都会转化为json串,若放在方法上,则只有特定的方法返回值会转化为json串
@ResponseBody
@RequestMapping("/ResponseBody")
public User testResponseBody(){
User user = new User();
user.setPassword("123");
return user;
}
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且同时为类中的每个方法添加了@ResponseBody注解
@RequestMapping("/down")
public ResponseEntity testResponseEntity(HttpSession session) throws Exception{
//获取servletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件真实路径
String realPath = servletContext.getRealPath("/img/hot.png");
//创建输入流
FileInputStream fileInputStream = new FileInputStream(realPath);
//串讲字节数组(fileInputStream.available():获取当前字节输入流所对应的文件所有的字节数;为的就是将文件全部字节都读到字节数组中)
byte[] bytes = new byte[fileInputStream.available()];
//将流读取到字节数组中
fileInputStream.read(bytes);
//创建HttpHeader对象设置响应头信息
MultiValueMap httpHeaders = new HttpHeaders();
//设置需要下载方式以及下载文件的名称
httpHeaders.add("Content-Disposition", "attachment;filename=hot.png");
//设置响应状态码
HttpStatus httpStatus = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity responseEntity = new ResponseEntity(bytes, httpHeaders, httpStatus);
//关闭输入流
fileInputStream.close();
return responseEntity;
}
文件上传的要求
commons-fileupload
commons-fileupload
1.4
@RequestMapping("/up")
public String testUp(MultipartFile photo,HttpSession httpSession) throws Exception {
//获取文件名,有后缀名
String filename = photo.getOriginalFilename();
//获取上传文件的后缀名
String hzName = filename.substring(filename.lastIndexOf("."));
//获取UUID(在相同的系统本次服务中唯一[防止上传相同文件名中的文件出现覆盖现象])
String u = UUID.randomUUID().toString();
//拼接新的文件名
filename=u+hzName;
//过去servletContext对象
ServletContext servletContext = httpSession.getServletContext();
//获取当前工程的真实路径
String path = servletContext.getRealPath("photo");
//创建path所对应的文件对象
File file = new File(path);
if (!file.exists()){
file.mkdir();
}
String finalPath=path+File.separator+filename;
//将photo所对应的文件直接上传到我们指定文件所对应的位置
photo.transferTo(new File(finalPath));
return "success";
}
注意:MultipartFile是用来封装上传的对象(使用前先配置文件上传解析器;注意导入依赖),对象名必须与表单上传的name相对应
注意:
将自己写的拦截器交给spring容器来管理,并进行容器扫描
@Component
public class FirstInterceptor implements HandlerInterceptor {
//在控制器方法执行之前执行该方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
//返回值为true表示放行,返回值为false表示拦截
return true;
}
//在控制器方法执行之后执行的方法
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
//在渲染视图完毕之后执行该方法
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
多个拦截器的执行顺序和在springMVC的配置文件中的配置有关,但每个方法的执行顺序不一样
注意:若拦截器中有某个拦截器的preHandle方法返回了false,则该拦截器之前的preHandle方法都会执行,所有拦截器的postHandle方法都不执行,拦截器的preHandle方法返回false之前的拦截器的afterCompletion()会执行
SpringMVC提供了处理控制器方法执行过程中出现的异常的接口:HandlerExceptionResolver、HandlerExceptionResolver接口的实现类:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver,其中自定义异常处理器:SimpleMappingExceptionResolver,如果不配置自定义异常解析器,那么就会使用默认的异常解析器
error
//全局异常处理
//里面的参数表示不管哪个类上只要加了里面的两个注解,那么都会被全局异常处理器来进行异常处理
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class ExceptionController {
//若当前控制器方法执行的过程中出现了下面异常,那么它就会执行下面方法来处理异常
@ExceptionHandler(ArithmeticException.class)
public String handleException(Throwable ex,Model model){
//用ex代表该类异常属性在请求域中共享
model.addAttribute("ex", ex);
return "error";
}
}
前言:使用注解和配置类的方式代替web.xml和springMVC配置文件的功能
//用来代替web.xml
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
//设置一个配置类,代替spring的配置文件
protected Class>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//设置一个配置类,代替springmvc的配置文件
protected Class>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//设置springmvc前端控制器的url-pattern
protected String[] getServletMappings() {
return new String[]{"/"};
}
//设置当前的过滤器
@Override
protected Filter[] getServletFilters() {
//创建编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
//创建处理请求方式过滤器
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter};
}
}
//将该类标识为配置类
@Configuration
//扫瞄具体包下的组件
@ComponentScan("cn.tedu.controller")
//开启mvc的注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
//默认的servlet处理静态资源
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//配置视图控制器
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
@Bean
//@Bean注解可以将标识的方法的返回值交给spring容器保存,bean的id为方法的方法名,也可以改@Bean("a"):id就变成a了
public CommonsMultipartResolver multipartResolver(){
return new CommonsMultipartResolver();
}
//配置拦截器
public void addInterceptors(InterceptorRegistry registry) {
FirstInterceptor firstInterceptor = new FirstInterceptor();
registry.addInterceptor(firstInterceptor).addPathPatterns("/**").excludePathPatterns("/a");
}
//配置异常解析器
public void configureHandlerExceptionResolvers(List resolvers) {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("java.lang.ArithmeticException", "error");
simpleMappingExceptionResolver.setExceptionMappings(properties);
//共享异常信息到请求域
simpleMappingExceptionResolver.setExceptionAttribute("ex");
resolvers.add(simpleMappingExceptionResolver);
}
//配置生成模板解析器
@Bean
public ITemplateResolver templateResolver(){
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(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;
}
}