目录
一、SpringMVC简介
1.什么是MVC
2.springmvc特点
二、环境搭建
1.配置web.xml
2.创建请求控制器
3.创建SpringMVC配置文件
三、@RequestMapping注解
1.@RequestMapping注解的功能
2.@RequestMapping注解的位置
3.@RequestMapping注解的属性
4.SpringMVC支持ant风路径
5.SpringMVC支持路径中的占位符
四、SpringMVC获取请求参数
1.通过servletAPI获取
2.通过控制器方法的形参获取请求参数
3.@RequestParam
4.@RequestHeader
5.@CookieValue
6.通过POJO获取请求参数
7.解决获取请求参数的乱码问题
五、域对象共享数据
1.使用servletAPI向request域对象共享数据
2.使用ModelAndView向request域对象共享数据
3.使用Model向request域对象共享数据
4.使用map向request域对象共享数据
5.使用ModelMap向request域对象共享数据
6.向session域共享数据
7.向Application域共享数据
六、SpringMVC的视图
1.ThymeleafView
2.转发视图
3.重定向视图
4.视图控制器view-controller
七、HttpServletConverter
1.@RequestBody
2.RequestEntity
3.ResponseBody
4.springmvc处理json
5.@RestController注解
6.ResponseEntity
八、文件上传和下载
1.文件下载
2.文件上传
九、拦截器
1.拦截器的配置
2.拦截器的三个抽象方法
3.多个拦截器执行顺序
十、SpringMVC的异常处理
1.基于配置的异常处理
2.基于注解的异常处理
十一、注解配置SpringMVC
1.创建初始化类,代替web.xml
2.创建WebConfig配置类,代替SpringMVC的配置文件
MVC是一种软件架构思想,将软件按照模型、视图、控制器来划分。
M
:Model
,模型层,指工程中的JavaBean
,作用是处理数据。
JavaBean分为两类:
Service
或Dao
对象,专门用于处理业务逻辑和数据访问。V
:View
,视图层,指工程中的html
或jsp
等页面,作用是与用户进行交互,展示数据。
C
:Controller
,控制层,指工程中的servlet
,作用是接收请求和响应浏览器。
MVC的工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller
接收,Controller
调用相应的Model
层处理请求,处理完毕将结果返回到Controller
,Controller
再根据请求处理的结果找到相应的View
视图,渲染数据后最终响应给浏览器。
导入依赖
org.springframework
spring-webmvc
5.3.1
ch.qos.logback
logback-classic
1.2.3
javax.servlet
javax.servlet-api
3.1.0
provided
org.thymeleaf
thymeleaf-spring5
3.0.12.RELEASE
commons-fileupload
commons-fileupload
1.3.1
com.fasterxml.jackson.core
jackson-databind
2.11.2
junit
junit
4.11
test
a>默认配置方式
此配置作用下,SpringMVC的配置文件默认位于web-inf下,默认名称为
SpringMVC
org.springframework.web.servlet.DispatcherServlet
SpringMVC
/
b>扩展配置方式
SpringMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springMVC.xml
1
SpringMVC
/
用@Controller注解标识一个普通的java类
/*用@Controller注解标识为控制层组件
将其交由IoC容器管理 */
@Controller
public class TestController {
}
text/html
application/json
测试
@Controller
public class TestController {
//@RequestMapping处理请求和控制器方法之间的映射关系
//localhost:8080/springMVC/index
@RequestMapping("/index")
public String index() {
//设置视图名称,会被视图解析器解析
return "index";
}
}
浏览器发送请求,如果请求符合前端控制器的url-pattern,请求就会被DiapatcherServlet处理。将请求地址和控制器中@RequestMapping
注解的value
属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf
对视图进行渲染,最终转发到视图所对应页面
将请求和处理请求的控制器方法关联起来,建立映射关系
标识一个类:设置映射请求的请求路径的初始信息
标识一个方法:设置映射请求请求路径的具体信息
如:
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
此时请求路径为/test/index
(a)value属性
是一个字符串数组,可以匹配多个请求地址所对应的请求
@RequestMapping(value = {"/index", "/hello"})
public String index() {
return "index";
}
(b)method属性:根据get或post匹配请求映射(不设置则任何请求都能匹配)
@RequestMapping(value = {"/a","/b"},method = {RequestMethod.GET,RequestMethod.POST})
可以@GetMapping @PostMapping等注解指定请求方式
@GetMapping("/test")
public String testGet() {
return "target";
}
(c)params属性
"param":要求请求映射所匹配的请求必须携带param请求参数
"!param":要求请求映射所匹配的请求必须不能携带param请求参数
"param=value":要求请求映射所匹配的请求必须携带param请求参数且param=value
"param!=value":要求请求映射所匹配的请求必须携带param请求参数但是param!=value
@RequestMapping(
value = "/index"
,params = {"username","password!=123456"})
//请求参数要有username password不能等于123456
public String index() {
return "index";
}
(d)headers属性
"header":要求请求映射所匹配的请求必须携带header请求头信息
"!header":要求请求映射所匹配的请求必须不能携带header请求头信息
"header=value":要求请求映射所匹配的请求必须携带header请求头信息且header=value
"header!=value":要求请求映射所匹配的请求必须携带header请求头信息且header!=value
针对@RequestMapping的value属性进行模糊匹配
?: 标识任意的单个字符
* :表示任意的0个或多个字符
/** : 表示任意的一层或多层目录
注意:在使用/**时,只能使用/**/xxx的方式,若写成/a**/,**会被当成两个单独的*被解析
@RequestMapping("/a?a/testAnt")
public String testAnt() {
return "target";
}
原始方式:/deleteUser?id=1
rest方式:/deleteUser/1
//将占位符{id} 中的值自动赋值给形参
@RequestMapping("/testPath/{id}")
public String testPath(@PathVariable("id")Integer id) {
return "target";
}
@RequestMapping("/testPath/{id}/{username}")
public String testPath(@PathVariable("id")Integer id, @PathVariable("username")String username) {
return "target";
}
(不推荐使用)
@RequestMapping("/testServletAPI")
//根据形参类型自动赋值
public String testServletApi(HttpServletRequest request) {
String str = request.getParameter("a");
return "target";
}
@RequestMapping("testParam")
//只要保证形参中的参数名和请求参数的名字保持一致,就可以自动进行赋值
public String testParam(String username,String password) {
System.out.println(username + " " + password);
return "target";
}
//如果有多个同名的请求参数,可以直接用字符串进行获取,参数会用逗号拼接起来
//也可以用字符串数组进行获取
前端请求的名字如果和后端不一样,可以用@RequestParam注解配置前端请求参数与形参的映射
@RequestMapping("testParam")
//只要保证形参中的参数名和请求参数的名字保持一致,就可以自动进行赋值
public String testParam(@RequestParam("name") String username, String password) {
System.out.println(username + " " + password);
return "target";
}
有value required defaultValue三个属性
value:指定为形参赋值的请求参数的参数名
required 设置为true表示需要有这个请求参数,默认值为true
defaultValue 当请求参数没有传输时,使用默认值为形参(不管required为true还是false)
将请求头信息与形参创建映射关系
public void testHeader(@RequestHeader(value = "Host",required = true,defaultValue = "Host") String host) {
System.out.println(host);
}
将cookie数据和控制器的形参创建映射关系
也有value required deaultValue三个属性
@RequestMapping("/testBean")
//User内部要提供set方法
//如果浏览器请求参数名与User属性名一致,就会自动为属性赋值
public String testBean(User user) {
System.out.println(user);
return "target";
}
在web.xml中
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceResponseEncoding
true
CharacterEncodingFilter
/*
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request) {
request.setAttribute("name","Jack");
return "target";
}
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
ModelAndView modelAndView = new ModelAndView();
//向请求与request共享数据
modelAndView.addObject("name","Jack");
//设置视图
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping("/testModel")
public String testModel(Model model) {
model.addAttribute("name", "Jack");
return "success";
}
@RequestMapping("/testMap")
public String testMap(Map map) {
map.put("name","Mike");
return "success";
}
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap) {
modelMap.addAttribute("name","Jack");
return "success";
}
Model、ModelMap、Map类型的参数本质上都是BindingAwareModelMap类型的
(建议使用servletAPI)
@RequestMapping("/testSession")
public String testSession(HttpSession session) {
session.setAttribute("name","Jack");
return "success";
}
@RequestMapping("/testApplication")
public String testApplication(HttpSession session) {
ServletContext application = session.getServletContext();
application.setAttribute("name","Jack");
return "success";
}
SpringMVC中的视图是View
接口,视图的作用渲染数据,将模型Model
中的数据展示给用户
SpringMVC视图的种类很多,默认有转发视图InternalResourceView
和重定向视图RedirectView
当工程引入jstl
的依赖(解决jsp中嵌入java代码的繁琐),转发视图会自动转换为JstlView
。
若使用的视图技术为Thymeleaf
,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView。
当控制器方法返回的视图名称没有任何前缀时,此时视图名称会被spirngMVC配置的(thymeleaf)视图解析器解析,视图名称拼接视图前缀和视图后缀,并通过转发进行跳转
当控制器方法中所设置的视图名称以“forward: ”为前缀时,创建InternalResourceView视图,此时视图名称不会被springMVC配置文件中所配置的thymeleaf视图解析器解析,而是会将前缀去掉,剩余部分作为最终路径通过转发的方式实现跳转
@RequestMapping("/index")
public String index() {
return "success";
}
@RequestMapping("/testForward")
public String testForward() {
//将index作为最终路径,通过转发进行跳转
//这里会转发到上面那个index中
return "forward:index";
}
@RequestMapping("/testRedirect")
public String testRedirect() {
//重定向
return "redirect:index";
}
在控制器方法中没有任何处理过程,仅仅用来跳转,只需要设置一个视图名称,可以将处理器方法使用view-controller标签进行表示
view-name中的视图名称会被thymeleaf视图解析器解析
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签
报文信息转换器,将请求报文转换为java对象,或将java对象转换为相应报文
提供了两个注解和两个类型@RequestBody,@ResponseBody,RequestEntity,
ResponseEntity
可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为标识的形参进行赋值
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody) {
System.out.println(requestBody);
return "success";
}
是封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参
@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntityrequestEntity) {
System.out.println(requestEntity.getHeaders());
System.out.println(requestEntity.getBody());
return "success";
}
用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody() {
return "I'm Jack";
}
结果
a>导入jackson依赖
com.fasterxml.jackson.core
jackson-databind
2.11.2
b>在springmvc的核心配置文件中开启mvc注解驱动
此时在HanlderAdaptor中会自动装配一个消息转器:MappingJackson2HttpMessageConverter, 可以将相应到浏览器的java对象转换为Json格式的字符串
c>在处理器方法上使用@ResponseBody注解进行标识
d>将Java对象直接作为控制器的返回值返回,就会自动转换为Json格式的字符串
@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser() {
return new User("1","男",12,"Jack","1234");
}
结果
是SpringMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并为其中的每个方法添加了@ResponseBody注解
用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
例:下面的文件下载
利用ResponseEntity实现文件的下载
@RequestMapping("/testDown")
public ResponseEntity testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity responseEntity = new ResponseEntity(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
添加依赖
commons-fileupload
commons-fileupload
1.3.1
配置SpringMVC文件上传解析器
以post方式提交,并添加属性enctype="multipart/form-data"
SpringMVC将form表单上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取文件名
String filename = photo.getOriginalFilename();
//防止文件名重复
//获取文件后缀名
String suffixName = filename.substring(filename.lastIndexOf("."));
//将UUID作为文件名
String uuid = UUID.randomUUID().toString();
filename = uuid + suffixName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
if (!file.exists()){
//如果文件夹不存在,创建文件夹
file.mkdir();
}
String finalPath = photoPath + File.separator + filename;
photo.transferTo(new File(finalPath));
return "success";
}
拦截器属于SpringMVC框架,只有使用了SpringMVC框架的工程才能使用
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
另一种配置拦截器的方式(这种方式也会拦截所有请求)
通过下面这种方式可以指定拦截哪些请求
preHandle()
:控制器方法执行之前执行,返回值表示是否拦截,返回true
放行,返回false
拦截
postHandle()
:控制器方法执行之后执行postHandle()
。
afterComplation()
:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
//实现HandlerInterceptor接口
public class FirstInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
//返回false拦截请求,返回true放行
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
a>若每个拦截器的proHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHanlde()按照配置顺序执行,postHandle()和afterCompletion()会按照配置的反序执行
b>若某个拦截器的proHandle()返回了false,preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterCompletion()会执行
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver
基于配置的异常处理
error
@ControllerAdvice //将当前类标识为异常处理的组件
public class ExceptionController {
// @ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
//ex表示当前请求处理中出现的异常对象
public String testException(Exception ex, Model model) {
model.addAttribute("ex", ex);
return "error";
}
}
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。 Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
//web工程的初始化类,用来代替web.xml
//需要继承AbstractAnnotationConfigDispatcherServletInitializer
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
//指定spring的配置类
@Override
protected Class>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//指定SpringMVC的配置类
@Override
protected Class>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//指定DispatcherServlet的映射规则 即url-pattern
@Override
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};
}
}
/* 代替SpringMVC的配置文件
1、扫描组件 2、视图解析器 3、view-controller
4、default-servlet-handler 5、mvc注解驱动
6、文件上传解析器 7、异常处理 8、拦截器 */
//将当前类表示为一个配置类
@Configuration
//扫描组件
@ComponentScan("com.cc.mvc.controller")
//mvc注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
//default-servlet-handler
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//创建一个拦截器
TestInterceptor testInterceptor = new TestInterceptor();
//添加拦截器 设置要拦截的请求路径
registry.addInterceptor(testInterceptor).addPathPatterns("/**").excludePathPatterns("/");
}
//配置视图控制
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
//文件上传解析器
public MultipartResolver multipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
return commonsMultipartResolver;
}
//异常处理
@Override
public void configureHandlerExceptionResolvers(List resolvers) {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException", "error");
exceptionResolver.setExceptionMappings(prop);
//设置在请求域中共享数据的键值,通过键获取异常信息
exceptionResolver.setExceptionAttribute("exception");
resolvers.add(exceptionResolver);
}
//--thymeleaf视图解析器(下面三个)
//配置生成模板解析器
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
// ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
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;
}
}