Spring MVC 框架

Spring MVC 框架

springMVC概念

Spring MVC 是由spring 框架提供的一个web 层框架的解决方法。至于MVC 是什么我在前边文章也有说明,MVC 分别指的是model(模型:三层架构中的服务层,持久层,基本的Bean 实体),View 视图层,也就是我们的前端展示给用户的界面。controller指的是我们的web 层,负责接收请求与处理响应。Spring MVC 本质还是我们熟悉servlet,spring MVC 通过对原生的servlet 进行了在封装,解决我们每一个请求都需要一个servlet 的问题,极大减少了我们重复代码的冗余。它还实现了我们请求参数的封装,减少了我们手动编写封装请求的冗余问题。spring MVC集成请求分发,参数绑定,视图解析,编码过滤等常用的组件,极大提高了我们的开发效率。

image-20200823174617632

springMVC执行流程分析(面试重点)

image-20200823175314923

1.当请求通过浏览器来到spring mvc时,请求首先来到 spring MVC的一个核心servlet 组件 DispatchServlet(请求转发)。

2.DisPatcherServlet 组件用于把请求进行转发。

3.转发的请求到达HandlerMapping 处理映射器,通过HandMapping 处理映射器把请求映射到指定的方法中。

4.然后在 我们提供的 controller层的方法进行处理,处理完的请求进行返回。

5.然后通过spring MVC 提供的 View resolver 视图解析器,把响应映射到指定的View 视图,如果在处理请求的方法上配置了@ResponseBody,不会在进行视图解析,而是直接向浏览器响应一段 json 或者 字符串。

6.在View 中把spring 提供的 model 对象中的数据进行渲染。

spring mvc 组件

spring mvc 为我们提供了三大核心组件 dispatcherServlet, handMapping,view resolver。

dispatcherServlet: 本质上是spring mvc 预先写好的一个 servlet, 这个 servlet 会把所有的请求拦下,然后进行请求转发

HandMapping: 处理映射器,负责接收由 disPatherServlet 转发的请求,然后把请求映射到指定的 controller 中的方法去进行处。

HandMappingAdapter: 处理器适配器,采用适配器的设计模式,负责具体执行 controller 中的方法,然后返回 model(spring MVC 封装的一个request 域,传递数据)和view 字符串。

View resolver: 视图解析器,经过处理完controller 处理完的请求,如果没有特别指定返回的json(@ResPonseBody,@RestController)会默认被视图解析器进行处理,把返回的view字符串映射到指定的前端页面视图,然后视图(模板引擎技术 jsp ,thremleaf,freemarker)会把 model 域中的数据渲染到页面。

关于spring MVC 组件在 web.xml 配置(tomacat 读取加载)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 加载Spring容器配置 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 设置Spring容器加载所有的配置文件的路径 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-*.xml</param-value>
    </context-param>

    <!-- 配置SpringMVC核心控制器 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置初始配置化文件,前面contextConfigLocation看情况二选一 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring-mvc.xml</param-value>
        </init-param>
        <!-- 启动加载一次 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--为DispatcherServlet建立映射  通过配置请求的DispatchServlet 在 / 路径接收所有请求然后进行请求的转发到 controller 匹配具体请求-->
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--spring MVC 内部集成的默认servlet 放行静态资源 spring 拥有静态资源拦截器,需要配置放行规则-->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.png</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.woff</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.woff2</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.*</url-pattern>
    </servlet-mapping>

    <!-- 防止Spring内存溢出监听器 -->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

    <!-- 解决工程编码过滤器 过滤所有地址 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置欢迎页面
    <welcome-file-list>
        <welcome-file>html/index.html</welcome-file>
    </welcome-file-list>
    -->
</web-app>

spring MVC 常用注解(使用 spring MVC 需要依赖 spring 框架)

@Controller 出现在类上,表明为一个 controller 层,会把对象加入 spring 的IOC 容器。

@RequestMapping: 可以出现在方法或类上,出现在类上表明请求URL的一级路径,出现在方法上代表此方法接收的请求, 默认支持 value(请求路径),method(请求方式),params (请求参数设置限定)

@RequestMapping(value = "/findUserInfoList",method = RequestMethod.GET)
@RequestMapping(value="/removeAccount",params= {"accountName","money>100"})

和它相同功能的注解还有 @GetMapping ,@PostMapping,@PutMapping,@DeleteMaping....

@RequestParm:用于把请求参数给控制器中的形参赋值,常出现在前后端参数名不一致的情况下

@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
@RequestParam(value="age",required=false)Integer age,User user)

spring MVC 默认会自动实现参数绑定,参数绑定可以到集合,基本类型,string,和我们自定义的实体,当然这样就要求我们前端传递参数名要与后端一致,Java实体呢,要求前端参数名与实体类字段对应,这样才能封装到实体类。

@RequestBody:用于获取请求体内容 key=value&key=value,get 方法不支持,不常用到。

@PathVaribale:出现在参数上,用来构建 restful 风格的api。

image-20200823193346974

image-20200823193440080
@RequestMapping(value="/testRestPUT/{id}",method=RequestMethod.PUT)
public String testRestfulURLPUT(@PathVariable("id")Integer id,User user)
@RequestMapping(value="/testRestPOST",method=RequestMethod.POST)
public String testRestfulURLPOST(User user)
@RequestMapping(value="/testRestDELETE/{id}",method=RequestMethod.DELETE)
public String testRestfulURLDELETE(@PathVariable("id")Integer id)
@RequestMapping(value="/testRestGET/{id}",method=RequestMethod.GET)
public String testRestfulURLGET(@PathVariable("id")Integer id)

@CookieValue: 用于获取cookie 中的数据到形参

@SessionAttribute:用于向 session 中传递数据,一般不使用

@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false)
                             
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class}) 
public class SessionAttributeController

@ModelAttribute:可以用于修饰方法和参数,出现在方法上表明此方法可以在在控制器方法(请求执行的方法)前执行,出现在方法上,常用来进行执行更新操作的数据库参数(关键数据不传递到前端,在数据库端补全)补全。出现在方法上用来进行参数的绑定。通常我们会把这两结合起来使用。

易混淆的点 Model 对象,Model 对象相当于Request 域,用来进行数据传递。@ModelAttribute 用来进行数据补全参数绑定

---------------------无返回值 map 集合参数补全绑定实例----------------------------
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
map.put("abc",user);
}
/**
* 模拟修改用户方法
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success"; }
-------------------有返回值 参数补全绑定实例-----------------------------------
 @ModelAttribute
public User showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
return user;
}
/**
* 模拟修改用户方法
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("user")User user) {
// 这里的user 是经过上面进行参数补全的user  
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success"; } 
----------------Model 对象演示 -----------------------------------------
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class}) 
public class SessionAttributeController {
/**
* 把数据存入 SessionAttribute
* @param model
* @return
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
*/
@RequestMapping("/testPut") 
public String testPut(Model model){ 
model.addAttribute("username", "泰斯特"); 
model.addAttribute("password","123456"); 
model.addAttribute("age", 31); 
//跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有
这几个参数
return "success"; 
}

@ResponseBody: 出现在方法,表明此方法不去走视图解析器,响应Json 数据的字符串

@RestController: 相当于 @ResponseBody +@Controller ,把类加入IOC ,并且返回的结果不走视图解析器

ModelAndView 是 SpringMVC 为我们提供的一个对象用来数据传递和设置返回视图

string 类型用于响应视图或者响应json字符串
void 获取原生API 操作
ModelAndView 参数,用来数据传递和设置返回视图   
----------- 响应视图--------------------
controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
//指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB-INF/pages/success.jsp
@RequestMapping("/testReturnString")
public String testReturnString() {
System.out.println("AccountController 的 testReturnString 方法执行了。。。。");
return "success"; }
---------- void 类型 采用servlet API 操作-------------------
@RequestMapping("/testReturnVoid")
public void testReturnVoid(HttpServletRequest request,HttpServletResponse response) 
throws Exception {
} 
-----------响应 json 字符---------------
@RequestMapping("/testReturnString")
@ResponseBody  
public String testReturnString() {
System.out.println("AccountController 的 testReturnString 方法执行了。。。。");
return "{'status':'success'}"; } 
--------- ModelAndView 对象 -------------------------------  
@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
ModelAndView mv = new ModelAndView();
mv.addObject("username", "张三");
mv.setViewName("success");
return mv; }

@CrossOrigin(origins = "*", maxAge = 3600):跨域注解

Spring mvc 下的请求与重定向

----- 请求转发------------------
@RequestMapping("/testForward")
public String testForward() {
System.out.println("AccountController 的 testForward 方法执行了。。。。");
return "forward:/WEB-INF/pages/success.jsp"; }
如果用了 formward:则路径必须写成实际视图 url,不能写逻辑视图。
它相当于“request.getRequestDispatcher("url").forward(request,response)”。使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法
------重定向 -------------
@RequestMapping("/testRedirect")
public String testRedirect() {
System.out.println("AccountController 的 testRedirect 方法执行了。。。。");
return "redirect:testReturnModelAndView"; }它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不
能写在 WEB-INF 目录中,否则无法找到。
关于spring MVC异常处理的补充

异常被分为运行期异常和预期异常,对于可捕获的预期异常,在三层开发,我们通常不再 dao 层和 service 层直接捕获处理,我们通常直接在这两层向上抛出,统一交由 controller 层捕获处理。spring mvc 支持定义异常在上层处理。

image-20200823213229555
/**
 自定义异常处理器
   主要是实现HandlerExceptionResolver 接口,实现 resolveException 异常解析方法,返回错误界面,CustomException 为我们自定义 extends Exception 的子类,在这里我们我们仅了解,spring MVC 支持自定义异常即可,自定义异常需要自己实现异常处理器HandlerExceptionResolver中的解析异常resolveException的方法。
   注意自定义的异常类我们需要把它加入到 IOC 容器,可以通过注解和配置两种方式。
   <bean id="handlerExceptionResolver"
class="com.itheima.exception.CustomExceptionResolver"/>
*/
@Commponent("handlerExceptionResolver")
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ex.printStackTrace();
CustomException customException = null;
//如果抛出的是系统自定义异常则直接转换
if(ex instanceof CustomException){
customException = (CustomException)ex; }else{
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
customException = new CustomException("系统错误,请与系统管理 员联系!");
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", customException.getMessage());
modelAndView.setViewName("error");
return modelAndView; } }

Spring mvc 还支持文件上传,具体就不再赘述,网上例子有很多。

补充说明: 上面我们介绍了spring MVC 的注解方式,如果使用原生的 ssm 项目,我们需要去在 spring MVC 的配置中配置 注解支持,或者采用上文 spring 说的配置类方式,如果采用 spring Boot ,我们只需要导入 web 模块的 start,其他的都帮我们配置好了。

<!--xml方式 开启 mvc 注解支持 (@Controller 属于spring 的注解) 这里我省略了约束-->
<!-- 注解扫描包 -->
    <context:component-scan base-package="com.hyg.im" />

    <!-- 开启注解 -->
    <mvc:annotation-driven />

过滤器与拦截器区别与联系(面试重点)

过滤器和拦截器都可以用来拦截处理请求,这算是他两相同的地方,其实本质上这两个属于不同的东西。

过滤器 filter:

1. 过滤器依赖于 servlet 容器,属于 Java web 原生API 提供的过滤拦截请求的接口
      2. 过滤器在 servlet 初始化时便进行了加载,加载在Servlet 容器中,常用来过滤器中修改字符编码,用户权限,修改 HttpServletRequest 中的一些参数:过滤非法字符。
      3. 过滤器无法像拦截器一样,可以通过 spring 注入 bean 对象,进行复杂业务处理。
      4. 过滤器主要是对 servlet 请求拦截,支持静态资源拦截处理。
      5. 过滤器过滤拦截在前

拦截器 Interceptor:

1. 拦截器依赖于 web 框架,由 web MVC 框架提供实现。在spring 中拦截器基于Spring MVC 框架,基于反射和动态代理,是AOP的典型应用。
        2. 拦截器是基于web 框架加载调用,初始化在 IOC 容器中。
        3. 可以通过spring 的依赖注入,完成复杂逻辑处理。
        4. 拦截器是对 controller 中请求进行拦截处理,对直接请求静态资源的请求不能有效拦截处理
        5. 拦截器发会作用在 过滤器执行在 filterChain.doFilter(request,response)之后,在 dispatcherServlet 分发完请求后。

image-20200823222416663
/**
spring mvc 实现拦截器需要实现HandlerInterceptor
*/
public class LoginIntercetor implements HandlerInterceptor {
    /**
     * 在进入请求前 controller 拦截 返回值决定是否进入请求
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println(" 尚未执行请求 拦截 还未返回结果 ");
        HttpSession session = httpServletRequest.getSession();
        Object username = session.getAttribute("username");
        // 登录成功
        if(username !=null) {return  true;}
        return false;
    }
/**
return ModelAndView之前进行,可以操控Controller    的ModelAndView内容。也就是说在 controller 方法执行完返回之前执行
*/
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println(" 执行完请求 拦截 还未返回结果 ");
    }
/**
在过滤器返回给前端前一步执行,也就是在chain.doFilter(request, response)之后执行
*/
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println(" return filter 之后 拦截 ");
    }
}
---------- spring MVC 配置文件 拦截器配置 多个组成拦截器链 ----
<!-- 配置拦截器 -->
<mvc:interceptors>
         <mvc:interceptor>
             <mvc:mapping path="/**"/>
             <mvc:exclude-mapping path="/index"/>
             <bean class="com.stack.Interceptor.LoginIntercetor"/>
         </mvc:interceptor>
</mvc:interceptors>

image-20200823221536787

多个拦截器同过滤器一样,可以组成拦截器链,按照拦截器在配置文件中的配置位置先后顺序执行。

使用springMVC带来的好处

上面写了这么多,spring MVC 的好处和易用性也都表现的十分明显。

  1. 提供了模块的内聚,通过 dispatcherServlet 和 handMapping 让不再一个请求一个 servlet
  2. 参数绑定的便捷,我们不再需要重复进行请求参数与Java 对象绑定
  3. 视图解析器和Model 对视图响应和数据传递更容易使用
  4. 拦截器对过滤器的补充与完善
  5. 对原生 servlet API 封装,使我们 web 开发更加高效

    > 在搭建ssm 或 springMVC 等设计的web 服务 tomcat 的项目
    >要把 需要依赖的 jar 包放到 WEB-INF 的目录下的 lib 目录中只有
    >存放在 此位置的第三方依赖才能正常被 tomcat 加载识别到。
    ### idea调试Web项目
    > idea 调试Java web 项目时,控制台会有三段日志信息可以查看,出现
    >错误时要查看这三部分日志定位错误
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值