springMVC环境:基于spring环境;spring-web,spring-webMVC,commons-BeanUtils,commons-Collections
jackson组件3个jar.
简单了解spring与springMVC父子容器的概念:
initServletBean()方法中: this.webApplicationContext = this.initWebApplicationContext(); //spring父容器对象 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); //去全局的ServletContext对象中获取对象 Object attr = ServletContext.getAttribute("WebApplication.ROOT"); //springmvc子容器对象:XmlWebApplicationContext WebApplicationContext wac = this.createWebApplicationContext(rootContext); //子容器持有了父容器 wac.setParent(rootContext); //子容器持有了全局的ServletContext对象 wac.setServletContext(this.getServletContext()); //加载springmvc.xml,进行包扫描,创建容器对象。 wac.refresh();前端控制器:在tomcat启东时,初始化springmvc子容器(N个bean对象),并持有了spring父容器。
写业务处理器(控制层):对于一个实体类的所有操作,都放在一个处理器类中。
处理器映射器:RequestMappingHandlerMapping
处理器适配器:RequestMappingHandlerAdapter
视图解析器:IntelResourceViewResolver
jackson消息转换器:MappingJackson2HttpMessageConverter
#springMVC
同步开发中,处理器方法之间的转发与重定向。
在返回的String以forward:或redirect:开头.
同步开发中不能使用,前后端分离的项目中使用最多
rest是对url的写法,描述性状态转移,url中不含动词
urlRequestMethoddataresturlRequestMethod/user/addpost请求体:{k:v,k,v}/userPOST添加/user/selectById?uid=1GET/user/1GET查询/user/updateByIdPOST请求体:{k:v,k:v}/userPUT修改/user/deleteById?uid=1GET/user/1DELETE删除注意点:
put和delete请求:如果请求体中的数据是key=value&key=value格式的话,收不到数据。可以通过配置FormContentFilter过滤器来接收数据。
把服务器端处理器方法内部产生的各种信息进行处理。
在web.xml中对不同的错误码进行错误页面配置。 <error-page> <error-code>404</error-code> <location>/404.html</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.html</location> </error-page>缺点:提示信息无法动态定义。只能够返回页面,在前端分离的情况下,不能使用。
局部异常处理:只对一个处理器类中的异常生效。 @ExceptionHandler(Exception.class) public ResponseEntity doException(Exception e){ String message = e.getMessage(); Map<String,String> datas = new HashMap<>(); datas.put("msg",message); datas.put("date",System.currentTimeMillis()+""); return ResponseEntity.ok(datas); }缺点:范围太小,只对一个类有效
全局异常处理:对所有处理器类中的异常生效。 public class MyExceptionHandler implements HandlerExceptionResolver { //适合于同步开发,当出现异常,转到一个自定义的异常页。 @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { HandlerMethod hm = (HandlerMethod)o; Method method = hm.getMethod(); String clzName = method.getDeclaringClass().getName(); String methodName = method.getName(); ModelAndView mv = new ModelAndView(); mv.setViewName("error"); mv.addObject("msg",e.getMessage()); mv.addObject("date",System.currentTimeMillis()+""); return mv; }缺点:只能够同步开发中使用。异步开发中不支持。
全局统一异常处理:项目中使用,在局部异常处理的基础上结合着@ControllerAdvice注解一起使用前端程序员调用后端接口,后端需要把执行结果返回前端(数字状态码,中文文字信息,数据)。
状态码枚举类;StatusBean;ResponseBean;自定义异常;定义全局的异常处理类;
同步开发,半分离异步开发。(前端资源和后端代码在一个项目中)
在web目录下的前端资源无法直接访问。
为什么jsp能访问,也是因为tomcat,tomcat中有默认的serlvet:default,jsp,当访问XXX.jsp进入JspServlet中处理。当我们访问XXX.html,XXX.css等非jsp后缀的时候,进入DispatcherServlet,前端控制器解析url,找处理器对象,找不到,则404.
解决方法1:在web.xml中配置defaultServlet <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.js</url-pattern> </servlet-mapping> 解决方式2:springMVC中有标签自动配置defaultServlet,建议使用这种。 <!--所有的静态资源都走DefaultServlet, default-servlet-name="default"--> <mvc:default-servlet-handler></mvc:default-servlet-handler> 解决方式3:springMVC中通过静态资源映射器,对静态资源进行处理。 <mvc:resources mapping="/static/**" location="/static/"></mvc:resources> <mvc:resources mapping="/page/**" location="/page/"></mvc:resources>springMVC的文件上传仍然基于apache common-fileupload。
添加fileupload;io两个文件上传的jar包;在springmvc.xml中配置文件上传解析对象。 <!--文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property><!--上传中文文件名--> <property name="maxUploadSize" value="50000000"></property><!--上传文件最大大小--> <property name="maxInMemorySize" value="10000000"></property><!--临时文件的存储域--> <property name="uploadTempDir" value="/upload/tmp"></property><!--临时文件存储目录--> </bean> 写文件上传处理器前端提交url:
@RequestParam只能用在key=value数据格式,只能用在简单类型上。
@RequestBody只能 用在{k:v}数据格式,只能用在自定义对象类型上,map上。
@PathValiable只能用来获取url内的变量。
前端提交的url传输数据提交方式后端获取数据/url?k=v&k1=v1数据在url上?后get可以直接加形参,@RequetParam/url/v数据在url内get|delete后端使用@PathValiable来获取uri中的变量/url数据在请求体,而且是json格式,无乱码post|put|delete后端使用@RequestBody来获取数据/url数据在请求体,而且是k=v&k=vpost|put|delete可以直接加形参,@RequetParam项目中使用全局统一异常处理:
自定义状态码枚举,自定义异常(持有了一个枚举对象)
定义一个全局统一的异常处理类,使用@ControllerAdvice注解。对所有RequestMapping做增强处理。
定义响应体。
静态资源处理:前端未分离
mvc:default-servlet-handler静态资源由DefaultServlet处理。不在走DispathcerServlet
文件上传下载:
添加两个jar包:commons-fileupload,commons-io
配置文件解析器:CommonsMultipartResolver,该bean对象的id必须是multipartResolver
在文件上传处理器中,表单参数类型写成MultipartFile对象即可。
类似于过滤器filter,拦截器是框架中的概念。
登陆拦截器是个项目中都会使用。权限拦截器
编写拦截器类 public class LoginInterceptor implements HandlerInterceptor { //前拦截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object login_user = session.getAttribute("LOGIN_USER"); if (login_user != null) { return true; } throw new MvcException(StatusEnum.NO_LOGIN); } } 配置拦截器 <mvc:interceptors> <mvc:interceptor> <!--拦截路径--> <mvc:mapping path="/**"/> <!--忽略路径--> <mvc:exclude-mapping path="/u/login"></mvc:exclude-mapping> <!--拦截器类--> <bean class="com.javasm.common.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>发起的请求与当前页面所在服务, 协议,ip,端口三者只要有一个不同,违反了浏览器的同源策略,造成跨域问题。
需要在服务器端配置响应头,告诉浏览器服务端允许这个客户端的请求:
响应头需要配置如下信息:
允许的域:http://127.0.0.1:8848
允许的请求头:
允许的请求方法:GET/POST/PUT/DELETE/OPTIONS预检.
是否允许请求携带cookie信息:
可以暴露给客户端的响应头:
跨域产生的问题:
问题1:请求不能正常响应。因为浏览器的同源保护(springmvc.xml中配置全局跨域)
解决方法:配置springMVC全局跨域设置mvc:cors
问题2:httpSession保存用户会话信息:每次请求服务器都会创建新的HttpSession对象,无法做到多次请求之间共享session中数据。
解决方法:前端axios请求配置withCredentials=true,表示请求时携带cookie
服务端跨越配置中允许接收客户端cookie,allow-credentials=“true”
如果使用chrome发现配置后仍然不行,开发中暂时先chrome://flags/,把samesite禁用了。
仍然存在的问题:
tomcat分布式部署的时候,多服务器之间的session共享问题(通过spring-session,结合redis使用)。
chrome浏览器的samesite同站点默认配置lax,不保存第三方的cookie问题。
解决方法2:JWT组件,token工具包
注意点:
在跨域的情况下,浏览器对POST,PUT,DELETE三种请求,会先向服务器发送预检请求,(检查服务端是否支持客户端的本次请求).
定义出事务管理器对象。
定义事务切面,切入点表达式使用注解方式。
总结:
拦截器在项目中登录拦截,权限拦截。
从HandlerInterceptor接口派生,重写preHandle前拦截。(在拦截方法中一定把OPTIONS请求放行,避免预检请求被拦着,造成跨域设置失败)
配置拦截器
跨域:
服务端:springMVC全局跨域配置或者配置跨域过滤器:
<mvc:mapping path="/**" allowed-origins=“http://127.0.0.1:8848” allowed-methods="" allowed-headers="" allow-credentials=“true”/>
登录用户的状态信息维护:
服务器端HttpSession保存用户登录信息:
客户端:axios配置携带cookie:axios.defaults.withCredentials = true;
服务端:allow-credentials=“true”
如果chrome浏览器不保存第三方的cookie,禁止chrome的samesite=lax。
