个人主页:胖虎不秃头
✨个人简介:Java领域新星创作者,随时准备跑路的大二学生
精品专栏:有这一个就够了
个人名言:知道的越多,不知道的越多
刷题神器:推荐一款算法刷题网站Nowcoder点击跳转刷题网站进行注册学习
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller
调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果
找到相应的View视图,渲染数据后最终响应给浏览器
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、
WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目
表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台
servlet
基于 MVC 架构,功能分工明确。解耦合。
就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的特定的接口和类。
方便整合Strtus,MyBatis,Hiberate,JPA 等其他框架。
在Controller, Service, Dao 都可以使用注解。方便灵活。使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource 在控制器类中注入 Service,在Service 类中注入 Dao。
执行流程说明:
所谓 SpringMVC 的注解式开发是指:
在代码中通过对类与方法的注解,便可完成处理器在 springmvc 容器的注册。注解式开发是重点。
项目案例功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息,在响应页面中显示该信息。
创建步骤:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.5.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
因为web的请求都是由Servlet来进行处理的,而SpringMVC的核心处理器就是一个DispatcherServlet,它负责接收客户端的请求,并根据请求的路径分派给对应的action(控制器)进行处理,处理结束后依然由核心处理器DispatcherServlet进行响应返回。
中央调度器的全限定性类名在导入的 Jar 文件 spring-webmvc-5.2.5.RELEASE.jar 的第一个包org.springframework.web.servlet下可找到。
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>*.actionurl-pattern>
servlet-mapping>
classpath:springmvc.xml
表示从类路径下加载SpringMVC的配置文件。
指定拦截以.action结尾的请求,交给核心处理器DispatcherServlet处理。
删除index.jsp页面,重新建index.jsp页面,因为自动生成的页面缺失指令设置。
开发页面,发出请求。
<a href="${pageContext.request.contextPath}/zar/hello.action">访问actiona>
在webapp目录上新添目录/admin。
在/admin目录下新建main.jsp页面。用来进行服务器处理完毕后数据的回显。
开发HelloSpringMvc.java–>控制器(相当于以前的servlet)。这是一个普通的类,不用继承和实现接口。类中的每个方法就是一个具体的action控制器。
@Controller
@RequestMapping("/zar")
public class HelloSpringMvc {
@RequestMapping("/hello")
public String one(){
return "main";
}
}
@Controller:表示当前类为处理器,交给Spring容器去创建对象。
@RequestMapping:表示路径映射。该注解可以加在类上相当于包名,还可以加在方法上相当于action的名称,都是来指定映射路径的。
<context:component-scan base-package="com.bjpowernode.controller">context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/">property>
<property name="suffix" value=".jsp">property>
bean>
SpringMVC框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器
InternalResouceViewResolver 中引入了请求的前辍与后辍。而action中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,视图解析器会自动完成拼接。
context:component-scan:用来进行包扫描,这里用于指定@Controller注解所在的包路径。
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
通过@RequestMapping 注解可以定义处理器对于请求的映射规则。
该注解可以注解在方法上,也可以注解在类上,但意义是不同的。
value 属性值常以“/”开始。
@RequestMapping 的 value 属性用于定义所匹配请求的 URI。
一个@Controller 所注解的类中,可以定义多个处理器方法。
不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI部分可以被抽取到注解在类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块(相当于包)的名称。URI 的请求是相对于 Web 的根目录。
换个角度说,要访问处理器的指定方法,必须要在方法指定 URI 之前加上处理器类前定义的模块名称。
示例:
提取后
@Controller
@RequestMapping("/zar")
public class HelloSpringMvc {
//相当于一个控制器处理的方法
@RequestMapping("/hello")
public String one() {
return "main";
}
@RequestMapping("/two")
public String two() {
return "main";
}
//客户端的请求:
//
//
@RequestMapping(value = "/hello", method = RequestMethod.POST)
public String one() {
return "main";
}
以上处理器方法只能处理 POST 方式提交的请求。
客户端浏览器常用的请求方式,及其提交方式有以下几种:
也就是说,只要指定了处理器方法匹配的请求提交方式为 POST,则相当于指定了请求发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用。
当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。
对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解
@RequestMapping注解的params属性通过请求的请求参数匹配请求映射
@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数
和请求映射的匹配关系
“param”:要求请求映射所匹配的请求必须携带param请求参数
<a th:href="@{/test(username='admin',password=123456)">测试@RequestMapping的
params属性-->/testa><br>
@RequestMapping(
value = {"/testRequestMapping", "/test"}
,method = {RequestMethod.GET, RequestMethod.POST}
,params = {"username","password!=123456"}
)
public String testRequestMapping(){
return "success";
}
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
注:
若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400:Parameter conditions “username, password!=123456” not met for actual
request parameters: username={admin}, password={123456}
@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射,来源页面
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信
息和请求映射的匹配关系
若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面
显示404错误,即资源未找到
前四种数据注入的方式,会自动进行类型转换。但无法自动转换日期类型。
在方法中声明一个和表单提交的参数名称相同的参数,由框架按照名称直接注入。
在方法中声明一个自定义的实体类参数,框架调用实体类中相应的setter方法注入属性值,只要保证实体类中成员变量的名称与提交请求的name属性值一致即可。
使用框架提供的一个注解@PathVariable,将请求url中的值作为参数进行提取,只能是超链接。restful风格下的数据提取方式。restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
请求与形参中的名字不对应,可以使用
@RequestParam(value="name1",required=true)String namea
来进行参数名称绑定。
在方法参数中声明一个request对象,使用request的getParameter()获取表单提交的数据,这样得到的数据还要手工进行数据类型的转换。
public String five(HttpServletRequest request){
int age=new Integer(request.getParameter("stuage"));
String name=request.getParameter("stuname");
System.out.println(age+"*********"+name);
return "main";
}
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器: spring-web-5.2.5.RELEASE.jar 的org.springframework.web.filter 包下的 CharacterEncodingFilter 类。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I2YGXSv6-1659882586542)(…/…/…/…/Pictures/Spring/wps15.jpg)]
使用@Controller 注解的处理器的方法,其返回值常用的有四种类型:
第一种:ModelAndView
第二种:String
第三种:无返回值void
第四种:返回对象类型
处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S1gMsHVb-1659882586543)(…/…/…/…/Pictures/Spring/wps16.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ojn4atP-1659882586543)(…/…/…/…/Pictures/Spring/wps17.jpg)](https://img-blog.csdnimg.cn/15a94715b6594994994f09713df9ff6f.jpeg)
当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配置前辍与后辍了。
对于处理器方法返回 void 的应用场景,应用在AJAX 响应处理。若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。我们SSM整合案例中的分页使用的就是无返回值。
项目案例:使用ajax请求返回一个JSON结构的学生.
实现步骤:
A.在pom.xml文件中添加依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.8version>
dependency>
B.添加jQuery的函数库,在webapp目录下,新建js目录,拷贝jquery-3.3.1.js到目录下
C.在页面添加jQuery的函数库的引用
<script src="js/jquery-3.3.1.js"></script>
D.发送ajax请求
function show() {
$.ajax({
url:"${pageContext.request.contextPath}/ajax.action",
type:"post",
dataType:"json",
success:function (stu) {
$("#oneStu").html(stu.name+"------"+stu.age);
}
});
}
E.开发action
@Controller
public class AjaxDemo {
@RequestMapping("/ajax")
@ResponseBody //此注解用来解析ajax请求
public Object ajax(){
Student stu = new Student("张三",22);
return stu;
}
}
F.在springmvc.xml文件中添加注解驱动
<mvc:annotation-driven>mvc:annotation-driven>
G.index.jsp页面
ajax访问服务器,返回一个学生
页面部分:
请求转发页面(默认)
请求转发action
重定向页面
重定向action
Controller部分:
@Controller
public class JumpAction {
@RequestMapping("/one")
public String one(){
System.out.println("请求转发页面(默认)");
//以前的访问方式 //request.getRequestDispatcher("/admin/main.jsp").forward(request,response);
//观察地址栏的变化: http://localhost:8080/one.action
//return "main"; //默认的访问方式是自动拼接前缀和后缀进行跳转
return "forward:/fore/user.jsp";//只要使用了forward:就可以屏蔽前缀和后缀的拼接,自己手工构建返回的全部路径+.jsp
}
@RequestMapping("/two")
public String two(){
System.out.println("请求转发action");
//观察地址栏的变化: http://localhost:8080/two.action
return "forward:/other.action";
//不使用forward:,就会是这样的路径 /admin/other.action/.jsp
}
@RequestMapping("/three")
public String three(){
System.out.println("重定向页面");
//观察地址栏的变化 http://localhost:8080/admin/main.jsp
return "redirect:/admin/main.jsp";
//只要使用了redirect:就可以屏蔽前缀和后缀的拼接
}
@RequestMapping("/four")
public String four(){
System.out.println("重定向action");
//观察地址栏的变化 http://localhost:8080/other.action
return "redirect:/other.action";
//只要使用了redirect:就可以屏蔽前缀和后缀的拼接
}
}
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view
controller标签进行表示
<mvc:view-controller path="/testView" view-name="success">mvc:view-controller>
注:
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需
要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:
JSP中内置对象
这些类型只要写在方法参数中就可以使用了。
1)HttpServletRequest 对象
2)HttpServletResponse 对象
3)HttpSession 对象
4)Model/ModelMap 对象
5)Map
示例:
@Controller
public class ParamAction {
@RequestMapping("/param")
public String param(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model,
ModelMap modelMap,
Map map){
//Map ,Model,ModelMap,request都使用请求作用域进行传值,
//所以必须使用请求转发的方式进行跳转,否则丢失数据
Student stu = new Student("张三",22);
request.setAttribute("requestStu",stu);
session.setAttribute("sessionStu",stu);
modelMap.addAttribute("modelMapStu",stu);
model.addAttribute("modelStu",stu);
map.put("mapStu",stu);
return "main"; //切记请求转发跳转
// return "redirect:/admin/main.jsp";//会丢失数据
}
}
注意Model,Map,ModelMap都使用的是request请求作用域,意味着只能是请求转发后,页面才可以得到值。
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
request.setAttribute("testScope", "hello,servletAPI");
return "success";
}
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//向请求域共享数据
mav.addObject("testScope", "hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("success");
return mav;
}
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testScope", "hello,Model");
return "success";
}
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testScope", "hello,Map");
return "success";
}
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testScope", "hello,ModelMap");
return "success";
}
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "hello,session");
return "success";
}
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "success";
}
日期类型不能自动注入到方法的参数中。需要单独做转换处理。
使用@DateTimeFormat注解,需要在springmvc.xml文件中添加
@RequestMapping("/submitone")
public String submitdateone(
@DateTimeFormat(pattern="yyyy-MM-dd")
Date mydate){
System.out.println(mydate);
return "dateShow";
}
@DateTimeFormat(pattern="yyyy-MM-dd")
public void setDate(Date date) {
this.date = date;
}
但这种解决方案要在每个使用日期类型的地方都去添加使用@DateTimeFormat注解,比较麻烦,我们可以使用@InitBinder注解来进行类中统一日期类型的处理。
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(sf, true));
}
这样在类中出现的所有日期都可以进行转换了。
需要在类中的成员变量的getXXX方法上加注解.
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
public Date getDate() {
return date;
}
需要使用国际化标签,先添加依赖
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
导入国际化的标签库
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
再使用标签显示日期
<c:forEach items="${list}" var="stu"> ${stu.name}-------${stu.age}-------
<fmt:formatDate value="${stu.date}" pattern="yyyy-MM-dd">
1)支持使用ConversionService 实例对表单参数进行类型转换;
2)支持使用 @NumberFormat 、@DateTimeFormat;
3)注解完成数据类型的格式化;
4)支持使用 @RequestBody 和 @ResponseBody 注解;
5)静态资源的分流也使用这个标签;
项目案例:
action:
@Controller
public class ShowAction {
@RequestMapping("/showIndex")
public String showIndex(){
System.out.println("index.............");
return "index";
}
@RequestMapping("/showMain")
public String showMain(){
System.out.println("main.............");
return "main";
}
@RequestMapping("/showLogin")
public String showLogin(){
System.out.println("login.............");
return "login";
}
@RequestMapping("/login")
public String login(String name, String pwd, HttpServletRequest request){
if("admin".equals(name) && "123".equals(pwd)){
return "main";
}
request.setAttribute("msg","用户名或密码不正确!");
return "login";
}
}
运行结果:
注意:在使用 ** 时,只能使用/**/xxx的方式, * *前后不能有任何字符,只能有//
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
1、日志记录:记录请求信息的日志
2、权限检查,如登录检查
3、性能检测:检测方法的执行时间
1)preHandle():在请求被处理之前进行操作
2)postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果
3)afterCompletion:所有的请求响应结束后(渲染视图完毕)执行善后工作,清理对象,关闭资源
1)继承HandlerInterceptorAdapter的父类
2)实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式
自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。
实现一个权限验证拦截器。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login">mvc:exclude-mapping>
<mvc:exclude-mapping path="/showLogin">mvc:exclude-mapping>
<bean class="com.bjpowernode.interceptor.LoginInterceptor">bean>
mvc:interceptor>
mvc:interceptors>
过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的。
Filter 处理中
Interceptor 前置
Interceptor 处理中
Interceptor 后置
Filter 处理中
①若每个拦截器的preHandle()都返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行
②若某个拦截器的preHandle()返回了false
preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false
的拦截器之前的拦截器的afterCompletion()会执行
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">errorprop>
props>
property>
<property name="exceptionAttribute" value="ex">property>
bean>
//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(ArithmeticException.class)
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}
REST:Representational State Transfer,表现层资源状态转移。
①资源
②资源的表述
③状态转移
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
操作 | 传统方式 | REST风格 |
---|---|---|
查询操作 | getUserById?id=1 | user/1–>get请求方式 |
保存操作 | saveUser | user–>post请求方式 |
删除操作 | deleteUser?id=1 | user/1–>delete请求方式 |
更新操作 | updateUser | user–>put请求方式 |
在web.xml中注册HiddenHttpMethodFilter
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter
filter- class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和
HiddenHttpMethodFilter
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter 原因:
在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的
request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:
String paramValue = request.getParameter(this.methodParam);
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
*指定spring的配置类
*@return
*/ @Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
/**
*指定SpringMVC的配置类
*@return
*/ @Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
/**
*指定DispatcherServlet的映射规则,即url-pattern
*@return
*/ @Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
*添加过滤器
*@return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceRequestEncoding(true);
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{encodingFilter, hiddenHttpMethodFilter};
}
}
@Configuration
public class SpringConfig {
//ssm整合之后,spring的配置信息写在此类中
}
@Configuration
//扫描组件@ComponentScan("com.atguigu.mvc.controller")
//开启MVC注解驱动@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
//使用默认的servlet处理静态资源@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
//配置文件上传解析器@Bean
public CommonsMultipartResolver multipartResolver(){
return new CommonsMultipartResolver();
}
//配置拦截器@Override
public void addInterceptors(InterceptorRegistry registry) {
FirstInterceptor firstInterceptor = new FirstInterceptor();
registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
}
//配置视图控制
/*@Override
public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index");
}*/
//配置异常映射
/*@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("ex"); resolvers.add(exceptionResolver);
}*/
//配置生成模板解析器@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;
}
}
@RequestMapping("/")
public String index(){
return "index";
}
DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
HandlerMapping:处理器映射器,不需要工程师开发,由框架提供
作用:根据请求的url、method等信息查找Handler,即控制器方法
Handler:处理器,需要工程师开发
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
ViewResolver:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
View:视图
作用:将模型数据通过页面展示给用户
用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。
DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:
a) 不存在
i. 再判断是否配置了mvc:default-servlet-handler
ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误
iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404 错误
b) 存在则执行下面的流程
根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。
DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
此时将开始执行拦截器的postHandle(…)方法【逆向】。
根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。
渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。
将渲染结果返回给客户端。