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执行异常解析器,用来对异常进行统一处理
-
-
用户发送请求至DispatcherServlet;解析URI
-
DispatcherServlet委托HandlerMapping根据解析的URI中的站点,如blog,映射到Handler,找到beanId为blog的控制器Controller
-
DispatcherServlet调用HandlerAdapter去匹配和执行正确的Controller处理业务,与Service交互产生结果;结果返回ModelAndView,再传回DispatcherServlet
-
DispatcherServlet将Model传给ViewResolver解析渲染,即将模型数据填充视图中,再返回来
-
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-未整理
-
Struts的工作原理和流程:https://www.cnblogs.com/quchengfeng/p/4916856.html