本文参考文章https://www.cnblogs.com/baiduligang/p/4247164.html。感谢作者提供的技术知识,我优化了一下。
目录
一、前言
二、spring mvc 核心类与接口
三、spring mvc 核心流程图
四、spring mvc DispatcherServlet说明
五、spring mvc 父子上下文的说明
六、springMVC-mvc.xml 配置文件片段讲解
七、spring mvc 如何访问到静态的文件,如jpg,js,css
八、spring mvc 请求如何映射到具体的Action中的方法
九、 spring mvc 中的拦截器:
十、 spring mvc 如何使用拦截器
十一、 spring mvc 如何实现全局的异常处理
十二、 spring mvc 如何把全局异常记录到日志中
十三、 如何给spring3 MVC中的Action做JUnit单元测试
十四、 spring mvc 转发与重定向 (带参数重定向)
十五、 spring mvc 处理ajax请求
十六、 spring mvc 关于写几个配置文件的说明
十七、 spring mvc 如何取得Spring管理的bean
十八、 spring mvc 多视图控制器
十九、
二十、 本文中springMVC.xml配置文件是核心,这里给一个下载地址
很多人对于刚开始工作经验时间不长的,大家很多地方不理解。我希望可以用白话让大家更可以理解。
springmvc我们为什么要学习呢?这可能大家有很多答案
我个人认为,springmvc学习起来很简单,比Struts2学习起来更快捷,更方便,更简洁。作为程序员,我们当然希望我们把更多的经历放在业务上。让我来比一下Struts2和springmvc吧。
springmvc的优点
1.首先springmvc的入口是Servlet
2.springMVC是基于方法开发的,它默认单例模式。它本身也可以为多例模式提供了方式,只需要我们在控制类里面加@scope(value="prototype")即可。它本身默认为单例模式
3.springmvc是基于方法开发的
4.springmvc的拦截器其实就是spring的AOP的一种实现方式
5.springmvc本身可以跟spring无缝衔接。
Struts2的优点
1.首先Struts2的入口是filter
2.它本身是基本类开发的。所谓基本类指的就是当你请求时Controller,Controller里的所有方法共享参数。
3.Struts2在集成spring时配置文件繁琐复杂,不利于开发。
以上图片引用原文作者
本人针对引用作者的原图我来补充一下
1.DispatcherServlet中会通过ServletContent(上下文对象:上下文对象的作用就是在程序初始化时,将一些信息注入到这个对象中),获取一些信息存放在ApplicationContext这个工具类中,ApplicationContext这个工具类底层采用的单例模式。所以当我们(Object)ApplicationContext.getBean("..xml")就可以得到我们注入bean的对像了。
2.DispatcherServlet-HandlerMapping(接口)-DefaultAnnotationHandlerMapping通过注解,把一个URL映射到Controller类上(order=0)或者SimpleUrlHandlerMapping (order=2147483646) 通过配置文件,把一个URL映射到Controller。如果找到控制器(Controller)-HandlerAdapter(接口适配器:就是找到你要请求那个方法的中转站)-AnnotationMethodHandlerAdapter类,通过注解或者SimpleUrlMethodHandlerAdapter(order=2147483646) 通过配置文件,把一个URL映射到Controller,把一个URL映射到Controller类的方法上,然后在查看该方法是否存在拦截器(-HandlerInterceptor (接口))-Controller-biz-dao-biz-Controller-ViewResolver接口-UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理或者InternalResourceViewResolver类,比上面的类,加入了JSTL的支持。在到View接口(-View接口)。以上是我对springmvc的原理过程的总结
//上面的-代表下一步走到那的意思(即交给谁来处理),order分优先级(值越小,代表优先级越高)
1.
2.
3.在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。
Xml代码
指明了配置文件的文件名,不使用默认配置文件名,而使用springMVC.xml配置文件。
其中
1、不写,使用默认值:/WEB-INF/
2、
3、
4、多个值用逗号分隔
Servlet拦截匹配规则可以自已定义,拦截哪种URL合适?
当映射为@RequestMapping("/user/add")时,为例:
1、拦截*.do、*.htm, 例如:/user/add.do
这是最传统的方式,最简单也最实用。不会导致静态文件(jpg,js,css)被拦截。
2、拦截/,例如:/user/add
可以实现现在很流行的REST风格。很多互联网类型的应用很喜欢这种风格的URL。
弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。想实现REST风格,事情就是麻烦一些。后面有解决办法还算简单。
3、拦截/*,这是一个错误的方式,请求可以走到Action中,但转到jsp时再次被拦截,不能访问到jsp。
如果想实现REST风格,办法我正可以先想一下,第一种是不是在我们进入spring容器之前,让Tomcat的Servlet我们先解析静态资源。第二种是让spring提供的Servlet来解析静态资源.
第一种自然可以想到在web.xml来启动Tomcat的Servlet来解析
不同的 servlet 容器/应用服务器,处理这些静态资源的 servlet 的名字不大一样:
Tomcat, Jetty, JBoss, and GlassFish:默认 Servlet 名字为 "default";
Google App Engine:默认 Servlet 名字为 "_ah_default";
Resin:默认 Servlet 名字为 "resin-file";
WebLogic:默认 Servlet 名字为 "FileServlet";
WebSphere:默认 Servlet 名字为 "SimpleFileServlet";
第二种自然启动spring提供的Servlet来解析,把自然肯定在对应的springmvc.xml(举例文件)里了
mapping:表示页面中使用到的路径
location:表示从该路径下进行查找
以上的配置:css,image,js放置在webapp目录下,页面中使用时:localhost:8080/css/aaa.css
注意:对于方法二,在tomcat下可以正常使用,但在resin下静态资源仍然找不到,最后发现,直接使用如下的配置就可以兼容tomcat和resin了
这种配置只支持有限的一些容器,对于spring不支持的容器,需要配置defaule-servlet-name进行指定。
对于不懂得可以看一下这个地址https://blog.csdn.net/u012730299/article/details/51872704这上面有很好的讲解
以上以上是对Rest请求方式总结,注明Rest是spring3.0以后的版本才有的。
在spring请求方式之前我们请求方式get和post2种,但是在spring3.0之后新增put和delete请求方式,这是针对spring的reset请求方式支持新增的,而且也新增注解@PathVariable来配合reset参数请求
以上是对Rest总结,注明Rest是spring3.0以后的版本才有的。
@Controller 声明Action组件
@Service 声明Service组件 @Service("myMovieLister")
@Repository 声明Dao组件
@Component 泛指组件, 当不好归类时.
@RequestMapping("/menu") 请求映射
@Resource 用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName")
@Autowired 用于注入,(srping提供的) 默认按类型装配
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody
@Scope("prototype") 设定bean的作用域
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。
后面,我们处理响应ajax请求时,就使用到了对json的支持。
后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,来完成测试,取的时候要知道是
大家思考一个问题springmvc怎么知道http方式请求时,它凭什么知道我们要去那个后台的Controller,那个方法呢?
1.很简单因为有HanflerMapper接口下有两个实现类DefaultAnnotationHandlerMapping(通过注解的方式)和SimpleUrlHandlerMapping(通过配置文件里的url)来找到相应的Controller。
2.我们该找那个具体方法了,我提到过适配器概念其实就是方法请求中转站。HandlerAdapter这个接口也有2个实现类,
AnnotationMethodHandlerAdapter类(通过注解)和SimpleUrlMethodHandlerAdapter(通过配置文件里的url)
以上是我讲springmvc.xml文件分解给大家展示。目的是让大家先有编程思想,而不是我先给大家。这样方便大家自己思考学习起来也深刻。最后springmvc.xml简单的,应该配置一些东西大家有一个总体的思想。
现在让大家来思考一下拦截器,它的作用,可以做一些什么事情,它是怎么找到要具体拦截那个方法吧,不能全都拦截对吧?
我们在现实中是不是都碰到过看例如爱奇艺里我可以浏览,但是当我们想看会员电影时大概只能看5分钟。然后就提示请看到会员。
1.拦截器可以做权限控制,日志处理,监控系统性能等。这个就是拦截可以做一些什么事
2.springmvc的拦截器就是Aop很好的体现和应用。关于AOP在spring深入理解会细讲
它是知道要拦截那些方法对吧。那它肯定跟DispatcherServlet有关,而且怎么知道的呢?
3.在springmvc.xml里配置的
Spring为我们提供了:
org.springframework.web.servlet.HandlerInterceptor接口,
org.springframework.web.servlet.handler.HandlerInterceptorAdapter适配器,
实现这个接口或继承此类,可以非常方便的实现自己的拦截器。
有以下三个方法:
Action之前执行:
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler);
生成视图之前执行
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView);
最后执行,可用于释放资源
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
参数中的Object handler是下一个拦截器。
这张图片是我粘贴别人的出处地址:https://www.cnblogs.com/Joke-Jay/p/7588580.html
如果出现错误了我应该怎么排查呢?我们应该用logger日志处理工具来处理吧。那就需要我们继承吧,我现在给大家提供一种简单方式。
1.加入日志jar包pom依赖
2.在resources目录下添加日志文件log4j.properties
3.配置web.xml日志监听
4:使用
1.
org.slf4j
slf4j-log4j12
1.7.5
2.#LOG_DIR:/usr/local/.../logs
LOG_DIR = E:\\logs //这里是日志文件的路径
#Level:ERROR,WARN,INFO,DEBUG
log4j.rootLogger = DEBUG,Console,FileInfo,FileError
log4j.appender.Console = org.apache.log4j.ConsoleAppender
log4j.appender.Console.Threshold = DEBUG
log4j.appender.Console.ImmediateFlush = true
log4j.appender.Console.Target = SYSTEM_OUT
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.appender.FileInfo = org.apache.log4j.DailyRollingFileAppender
log4j.appender.FileInfo.Threshold = INFO
log4j.appender.FileInfo.ImmediateFlush = true
log4j.appender.FileInfo.Append = true
log4j.appender.FileInfo.DatePattern = '_'yyyy-MM-dd'.log'
log4j.appender.FileInfo.encoding=UTF-8
log4j.appender.FileInfo.File = ${LOG_DIR}/info
log4j.appender.FileInfo.layout = org.apache.log4j.PatternLayout
log4j.appender.FileInfo.layout.ConversionPattern = [%-5p][%d{ISO8601}]%m%n
log4j.appender.FileError = org.apache.log4j.DailyRollingFileAppender
log4j.appender.FileError.Threshold = ERROR
log4j.appender.FileError.ImmediateFlush = true
log4j.appender.FileError.Append = true
log4j.appender.FileError.DatePattern = '_'yyyy-MM-dd'.log'
log4j.appender.FileError.encoding=UTF-8
log4j.appender.FileError.File = ${LOG_DIR}/error
log4j.appender.FileError.layout = org.apache.log4j.PatternLayout
log4j.appender.FileError.layout.ConversionPattern = [%-5p][%d{ISO8601}]%m%n
log4j.appender.cn.yivi.service.pay = info,pay
log4j.additivity.cn.yivi.service.pay = false
log4j.appender.pay = org.apache.log4j.DailyRollingFileAppender
log4j.appender.pay.Threshold = INFO
log4j.appender.pay.ImmediateFlush = true
log4j.appender.pay.Append = true
log4j.appender.pay.DatePattern = '_'yyyy-MM-dd'.log'
log4j.appender.pay.encoding=UTF-8
log4j.appender.pay.File = ${LOG_DIR}/pay
log4j.appender.pay.layout = org.apache.log4j.PatternLayout
log4j.appender.pay.layout.ConversionPattern = [%-5p][%d{ISO8601}]%m%n
3.
log4jConfigLocation
classpath:log4j.properties
org.springframework.web.util.Log4jConfigListener
4.final Logger logger = LoggerFactory.getLogger(UserInfoService.class);
以上是我对日志的配置过程的总结,方式很多。我找了一个最方便,最常用的方式
大家是不是我们错误的日志是不可能给用户看呢对吧,一旦出现了错误。我们只能给用户看统一的错误页面,不是一个错误对应一个错误页面。我们也做不到。所有做一个统一的错误页面,一旦发生异常我们统一给用户看的,在springmvc中我该怎么做呢?
这里提供给大家2种方式
1.web.xml增加
web.xml
Archetype Created Web Application
dispatcher
org.springframework.web.servlet.DispatcherServlet
1
dispatcher
/
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encodingFilter
/*
java.lang.Throwable
/WEB-INF/views/error/404.jsp
404
/WEB-INF/views/error/404.jsp
500
/WEB-INF/views/error/500.jsp
TestController.java
package com.controller;
import com.log.Log;
import com.remote.RemoteDemo;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by sunjf on 2016/6/26.
*/
@Controller
public class TestController {
@Log(desc = "log测试")
@RequestMapping(value = "test1")
public String test1(){
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "sun");
jsonObject.put("password", "123");
// String result = RemoteDemo.remoteJsonRequest("http://localhost:8080/test2?username=sun&password=123", 5000, jsonObject);
//System.out.println(result);
return "error/success1";
}
}
注:该方法跳转页面为success1.jsp,从项目结构中可以看出,我们的项目中是没有这个页面的
index.jsp
Hello World!
404.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
404
404
未能找到您访问的资源。
运行结果
访问链接
访问结果
2.自定义的方式:
2.1.我们在WEB-INF/views/commons/error(目录自己定)新建我们自定义的错误页面,404.html, 500.html等等
2.2.SimpleMappingExceptionResolver只实现映射关系,我们还需要通过配置web.xml来实现。
404
/error/404.html
500
/error/500.html
2.3.在spring-mvc配置文件中将404.html、500.html等设置为资源文件,避免被springmvc再次拦截。
<mvc:resources mapping="/error/**" location="/WEB-INF/views/commons/error/" />
2.4.配置SimpleMappingExceptionResolver。
class ="org.springframework.web.servlet.handler. SimpleMappingExceptionResolver">
name ="exceptionMappings">
key ="ResourceNotFoundException" value="common/error/resourceNotFoundError" />
key =".DataAccessException" value="common/error/dataAccessError" />
name ="statusCodes">
key ="common/error/resourceNotFoundError" value="404" />
key ="common/error/dataAccessError" value="500" />
感谢作者提供的:具体详细请参考https://www.cnblogs.com/baiduligang/p/4247164.html和https://www.cnblogs.com/sunjf/p/springmvc_error_view.html
springmvc中有转发和重定向这一概念,即forward(转发)和redirect(重定向),虽然我们实际中很少用,但是重定向可以解决跨域问题,还可以防止from重复
Xml代码
在web.xml中:
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">