SpringMVC

1 MVC

  • MVC模型:

    • model:数据模型,包含数据Dao和行为Service

    • view:视图,模型的展示

    • controller:控制器,连接模型和视图;接收请求,委托给模型进行处理,处理结果返回给视图

  • MVC框架的任务:

    • 改善Servlet开发:传统的每个请求要手动去匹配Servlet甚至方法,而MVC添加一层中间调度,前端只需与调度层接触,不同请求由调度器分发到不同处理器

    • 将URL映射到java类或方法

    • 封装前端提交的请求和数据

    • 处理请求,封装响应数据

    • 渲染响应数据

  • URL:http://localhost:8080/blog/doGet/?:第一层为服务器域名,后面一层blog为部署在服务器上的web站点,doGet为控制器,最后可能携带请求参数

2 SpringMVC

2.1 SpringMVC

  • 基于Java组件实现的MVC轻量级框架;和Spring的其他基础结构紧密集成;可任意使用包含JSP在内的各种视图技术;易于扩展

  • DispatcherServlet:核心;将请求分发到不同的处理器;基于注解@Controller声明;继承自FrameworkServlet -> HttpServlet,包含各种Resolver/Adapter属性

2.1.1 开发流程

  • web.xml中配置DispatcherServlet:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://java.sun.com/xml/ns/javaee"
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
            id="WebApp_ID" version="3.0"
    >
        <!-- 配置上下文加载监听器,用于加载spring.xml的配置(父配置,配置整个应用,如数据源等) -->
        <listener>
            <listener-class>org.springframework.web.context.ContextloaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring.xml</param-value>
        </context-param>
            
        <!-- 配置Servlet,前端控制器配置,引用配置文件,以及它映射处理的域 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 控制器加载spring-mvc.xml配置(子配置,配置控制器) -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </init-param>
            <!-- 随服务器启动而启动 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!-- url-pattern配置请求映射到的Servlet为所有 -->
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
            <!-- 注意与/*的区别:包含了JSP,因为JSP实质也是一个Servlet,会造成循环;而后者过滤所有文件,则可能404 -->
        </servlet-mapping>
    
        <!-- 使用SpringMVC的字符过滤器 -->
        <filter>
            <filter-name>characterEncodingFilter</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>
        </filter>
        <filter-mapping>
            <filter-name>characterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- 使用restful -->
        <filter>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>

  • 基于注解:基于web servlet3.0的开发,很少使用web.xml方式

    • 编写继承HttpServelt或其他衍生Servlet的自定义Servlet,重写doGet(),doPost()等方法,@WebServlet标注;同理@webFilter等注册Filter,Listener;即配置文件中的各种标签都已经有对应的接口;然后页面访问

  • 实际开发中所用:编写实现Controller的返回ModelAndView的handleRequest()的自定义控制器,setViewName(jspPage)返回指定页面;Spring配置文件中将Controller定义为Bean,beanId即为请求路径;不需要将此Servlet在web.xml中配置;一个控制器中只有一个方法是致命缺点

    • 方法的返回字符串自动被视图解析器处理,拼接前缀和后缀
    • 方法参数使用Model等封装数据到Attribute
    • 方法上@RequestMapping的值即为前端请求URL;类上@RequestMapping设置多层URL
    • 属性produces设置接收数据的类型和编码,如"application/json;charset=utf-8";但SpringMVC提供消息转换配置来统一管理接收的json数据
      <!--测试其他文件如service下的事务和AOP织入等,扫描com.springmvc-->
      <context:component-scan base-package="com.springmvc.controller"></context:component-scan>
      ​
      <!--开启使用注解方式的支持,如此省略了映射器和适配器的配置-->
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      <tx:annotation-driven></tx:annotation-driven>
      <mvc:annotation-driven></mvc:annotation-driven>
      <!--过滤静态资源-->
      <mvc:default-servlet-handler></mvc:default-servlet-handler>

  • Spring配置文件中< bean>定义各种Resolver、Adapter、Mapping

    <bean class="处理器映射器"></bean>
    <bean class="处理器适配器"></bean>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

2.1.2 执行流程

  • 核心组件:

    • DispatcherServlet:前端主控制器

    • HandlerMapping:处理器Handler映射器,根据请求携带的url信息查找处理器Handler。每个请求都需要对应的Handler处理

    • HandlerAdapter:处理器Handler适配器,SpringMVC为了统一Handler的调用方式,不直接调用处理器Handler,而是通过HandlerAdapter调用

    • ViewResolver:视图解析器,用来将字符串类型的视图名称解析为View类型的视图;ViewResolver需要找到渲染所用的模板和所用的技术,即视图的类型,进行渲染,渲染过程交由不同的视图自己完成

    • MultipartResolver:文件上传解析器,主要用来处理文件上传请求

    • HandlerExceptionResolver:Handler执行异常解析器,用来对异常进行统一处理

  1. 用户发送请求至DispatcherServlet;解析URI

  2. DispatcherServlet委托HandlerMapping根据解析的URI中的站点,如blog,映射到Handler,找到beanId为blog的控制器Controller

  3. DispatcherServlet调用HandlerAdapter去匹配和执行正确的Controller处理业务,与Service交互产生结果;结果返回ModelAndView,再传回DispatcherServlet

  4. DispatcherServlet将Model传给ViewResolver解析渲染,即将模型数据填充视图中,再返回来

  5. DispatcherServlet将响应Model渲染成视图View,View返回给浏览器供浏览

2.1.3 与前端数据交互

  • 普通参数方式:

    • 数据会被封装为方法入参,参数名一致

    • 参数前用@RequestParam(name),则请求必须带有该参数

      • defaultValue:设置默认值

      • value:设置参数别名,此时参数别名必须与请求参数名一致,参数名可不同

    • 例:public String add(String userName) {}

  • 对象方式:

    • 提交数据为对象,则入参为后端bean对象,且保持表单域name属性和bean对象属性名一致,否则返回null

    • 例:public String add(User user) {}

  • 原始方式:

    • request.getParameter("userName")

    • 例:public String add(HttpServletRequest request)

    • 方法参数可添加HttpServletResponse,构造返回数据

  • 请求参数占位方式:

    • @PathVariable()将url中的占位参数{userName}绑定到方法中的参数上

    • 例:@GetMapping("/user/{userName}"); public String query(@PathVariable("userName") String userName)

  • json方式:

    • 前端提交的数据以json串格式(上面几种方法都是表单数据格式)

    • 例:@PostMapping(value = "/user/add", produce = {"application/json;charset=UTF-8"}) @ResponseBody public String add(@RequestBody User user) {}

    • produce:指定返回值类型和字符编码;若返回json且当有@ResponseBody(这就是返回json)时可省略

  • 结果返回与跳转:设置ModelAndView/Model/ModelMap等的Attribute

    • 视图解析器:解析后拼接前后缀

    • 转发:默认

    • 重定向:与视图解析器不兼容,否则拼接redirect后一定报错

    • @ResponseBody:不经过视图解析器,直接返回字符串;@RestController是@ResponseBody和@Controller结合

2.1.4 其他

  • 乱码问题:

    • 使用request.setCharacterEncoding("utf-8")无作用,说明入参时已经乱码

    • 配置过滤器:实现Filter接口的doFilter();然后web.xml中配置该过滤器,且配置过滤URL为/*;一般直接使用SpringMVC提供的过滤器CharacterEncodingFilter

  • 拦截器:

    • 特殊的过滤器,只会过滤控制器方法,忽略静态资源;AOP原理;过滤器必须重写doFilter()

    • 定义拦截器:实现HandlerInterceptor接口;可以重写preHandle()等方法;配置拦截器即拦截path

      • 应用:用户登录拦截

2.1.5 Restful风格

  • 传统资源操作方式:get和post,如http://localhost:8080/blog/save.action,名字体现操作,带参数如?id=1为get请求

  • Restful:请求方式增加delete,put等;如http://localhost:8080/blog为post增,也可为put改,带参数/1可为get查,或delete删;遇到同名但不同请求方式时,默认get,前端可指定具体请求方式method

    • @PathVariable:用在方法参数前,绑定参数的值到请求的url模板变量中,如@RequestMapping(/blog/{id})

    • @RequestMapping可指定method具体请求方式,或直接替换为对应的@XXXMapping()

2.2 json

  • 用于前后端数据交换;注意,此时请求传递的是json格式数据

    {
        "name": "myName",
        "age": 11
    }
    // 上面为json格式的数据,下面为form-data表单格式的数据
        name: myName
        age: 11
    // 传递数组,数组中是json格式数据
    [
        {...},
        {...}
    ]
    • 虽然格式不同,但后端接收方式相同,区别在于参数是json时使用@RequestBody,而不是@RequestParam,如

      @PostMapping(...)
      // 使用Map或者JSONObject(JSONObject底层实现了Map)
      public String getParams(@RequestParam Map<String, Object> params) {
      // public String getParams(@RequestBody JSONObject jsonParams) {
          String name = params.get("name");
      }
      // 使用数组
      public String getParams(@RequestParam String[] params) {
          for (String param: params) {
              name = param;
          }
      }
      // 使用对象
      public String getParams(@RequestBody User user) {
          name = user.getName();
      }
      // 接收文本:HttpServletRequest,通过request.getInputStream()读取流中数据
      ​
      // 接收元素类型为json数据的数组:将User存储在集合中,如@RequestBody List<User> users,然后遍历该集合

    • 后端发送json数据到POST请求中,详见SpingBoot的RestTemplate

  • json:JS对象标记,轻量级数据交换格式;采用独立于编程语言的文本格式表示和存储数据,结构清晰简洁,便于人阅读和机器解析与生成,传输高效

  • 格式:对象表示为"key":"value";数据由逗号分开;花括号保存对象;方括号保存数组或集合;本质是一个字符串

  • 前端:

    • 将JS对象转回json字符串:var jsonString = JSON.stringify(user);打印显示{ "name": "name", age: "10"},注意区别于JS对象;stringgify即传化

    • 将json串解析为对象:var obj = JSON.parse(jsonString);格式检查,符合才解析;安全

    • eval():解析任意数据;不安全

  • 后端对数据的处理:

    • 使用第三方依赖:提供了大量数据解析和转换的工具类

      • jackson:须实例化类,调用相对繁琐;如ObjectMapper,其writeValueAsString(obj)直接将java对象或集合转为字符串输出

      • fastJSON:提供大量静态方法,调用简洁方便;反序列化性能略差;提供JSONObject即json对象,底层为Map;JSONArray数组对象,底层为List;JSON转换两者,如toJSONString(),parseObject()

      • 简单使用:直接配合@ResponseBody,将后端返回的数据转为json串响应回前端;页面发送请求后页面可见json数据;前后端分离,即后端只需返回json串,由前端自动去渲染

  • 应用举例:

    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import lombok.Data;
    ​
    /**
     * 前后端数据格式转换:常用于系统中去调用第三方请求,此时需要获取http请求中的数据,此数据通常都是一个很长的json串
     */
    public class JsonUtil {
        public static void main(String[] args) {
            // 将json字符串转为java对象:使用alibaba的JSONObject的静态方法,以及参数2的java对象反射
            Result result = JSONObject.parseObject("{\"data\":\"123\",\"flag\":true,\"message\":\"message result\"}",
                     Result.class);
            System.out.println(result);
    ​
            // 将内存中的JSONObject即json对象,或者JSONArray即json数组,转换为java对象
            // 前端传递的数据格式如:
            // {
            //     data1: {....},
            //     data2: [...]
            // }
            JSONObject jsonObject = new JSONObject(); // 同理,使用alibaba的
            JSONArray jsonArray = new JSONArray();
            jsonObject.put("data", "123"); // JSONObject实现了Map
            jsonObject.put("flag", true);
            jsonObject.put("message", "message result");
            result = jsonObject.toJavaObject(Result.class);
            System.out.println(result);
            // jsonArray.add(....); // JSONArray实现了List
    ​
            // 将java对象转为json字符串
            jsonObject = (JSONObject) JSONObject.toJSON(result);
            System.out.println(jsonObject);
        }
    }
    ​
    // 普通的javaBean
    @Data
    class Result {
        private String data;
        private boolean flag;
        private String message;
    }


3 Struts-未整理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值