springMVC基本知识

来源:互联网 发布:基金从业资格考试知乎 编辑:程序博客网 时间:2024/06/16 04:24
一.核心类与接口
DispatcherServlet————前置控制器
HandlerMapping接口————处理请求的映射
HandlerMapping接口的实现类:
SimpleUrlHandlerMapping:通过配置文件,把一个url映射到Controller
DefaultAnnotationHandlerMapping:通过注解,把一个url映射到Controller类上
HandlerAdapter接口————处理请求的映射
AnnotationMethodHandlerAdapter类,通过注解,把一个url映射到Controller类的方法上
Controller接口 ————控制器
由于我们使用了@Controller注解,添加了@Controller注解的类就可以担任控制器(Action)的职责,所以我们并没有用到这个接口
HandlerInterceptor接口————拦截器
我们自己实现这个接口,来完成拦截器的工作
ViewResolver接口的实现类
UrlBasedViewResolver类,通过配置文件,把一个视图名交给到一个View来处理
InternalResourceViewResolver类,比上面的类,加入了jstl的支持
View接口
JstlView类
LocalResolver接口
HandlerExceptionResolver接口————异常处理
SimpleMappingExceptionResolver实现类
ModelAndView类

二. DispatcherServlet说明
使用Spring MVC,配置DispatcherServlet是第一步
DispatcherServlet是一个Servlet,所以可以配置多个DispatcherServlet
DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自己定义,把拦截下来的请求,依据某某规则分发到目标Controller来处理
“某某规则”:是根据你使用了哪个HandlerMapping接口的实现类的不同而不同
例子:
1、
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup><!--设置启动顺序,让这个Servlet随Servlettp容器一起启动-->
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.do</url-pattern><!--拦截*.do为结尾的请求-->
</servlet-mapping>
</web-app>
在DispatcherServlet的初始化过程中,框架会在web应用的WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml的配置文件,生成文件中定义的bean
2、
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/springMVC.xml</param-value><!---->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern></url-pattern>
</servlet-mapping>
<1>、指明了配置文件的文件名,不使用默认配置文件名,而使用springMVC.xml配置文件
<2>、其中<param-value>**.xml</param-value>可以使用多种写法:
1、不写,使用默认值:/WEB-INF/<servlet-name>-servlet.xml
2、<param-value>/WEB-INF/classes/springMVC.xml</param-value>
3、<param-value>classpath*:springMVC-mvc.xml</param-value>
4、多个值用逗号分隔
<3>、Servlet拦截匹配规则可以自己定义
1、拦截*.do,例如:/user/add.do,弊端:所有的url都要以.do结尾。不会影响访问静态文件
2、拦截/app/*,例如:/app/user/add,弊端:请求的url都要包含/app,@RequestMapping(*/user/add*)中不必须包含/app
3、拦截/,例如:/user/add,弊端:对jpg,js,css静态文件的访问也被拦截不能正常显示
4、拦截/*,可以走到Action中,但转发到jsp时再次被拦截,不能访问到jsp


三.springMVC-mvc.xml配置文件
<!--自动扫描的包名-->
<context:component-scan base-package="com.app,com.core,JUnit4"></context:component-scan>
<!--默认的注解映射的支持-->
<mvc:annotation-driven/>
<!--视图解释类-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/><!--前缀-->
<property name="suffix" value=".jsp"/><!--后缀,可为空,方便实现自己的依据扩展名来选择试图解释类的逻辑-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
<!--拦截器-->
<mvc:interceptors>
<bean class="com.core.mvc.MyInteceptor"/>
</mvc:interceptors>
<!--对静态资源文件的访问    方案一(二选一)-->
<mvc:default-servlet-handler/>
<!--对静态资源文件的访问    方案二(二选一)-->
<mvc:resources mapping="/images/**"   location="/images/"/>
<mvc:resources mapping="/js/**"   location="/js/" />
<mvc:resources mapping="/css/**"   location="/css/"/>

(1)、<context:component-scan/>扫描指定的包中的类上的注解,常用的注解有:
@controller声明Action组件
@Service声明service组件 例如@Service("myMovieList")
@Repository声明Dao组件
@Component泛指组件,当不好归类时
@RequestMapping("/menu")请求映射
@Resource用于注入,(j2ee提供的)默认按名称装配,@Resource(name="beanName")
@Autowired用于注入,(spring提供的)默认按类型装配
@Transactional(rollbackFor={Exception.class})事务管理
@ResponseBody
@Scope(*prototype*)设定bean的作用域
(2)、<mvc:annotation-driven /> 是一种简写形式,完全可以手动配置替代这种简写形式,简写形式可以让初学都快速应用默认配置方案。
<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter
两个bean,是spring MVC为@Controllers分发请求所必须的。并提供了:数据绑定支持,@NumberFormatannotation支持,
@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。后面,我们处理响应ajax请求时,
就使用到了对json的支持。后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping
与AnnotationMethodHandlerAdapter 两个bean,来完成测试,取的时候要知道是<mvc:annotation-driven />这一句注册的
这两个bean。


四、如何访问到静态的文件,如jpg,js,css
如果你的DispatcherServlet拦截“*.do”这样的url,就不存在访问不到静态资源的问题。
如果你的DispatcherServlet拦截“/”,拦截所有的请求,同时对*.js,*.jpg的访问也就被拦截了

方案一:激活Tomcat的defaultServlet来处理静态文件
<serlvet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<serlvet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<serlvet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
要为每一种静态文件配置一个,要写在DispatcherServlet的前面,让defaultServlet先拦截,这个就不会进入spring了
Tomcat,Jetty,JBoss,GlassFish默认Servlet的名字:default
Google App Engine默认Servlet的名字:_ah_default
Resin默认Servlet的名字:resin-file
WebLogic默认Servlet的名字:FileServlet
WebSphere默认Servlet的名字:SimpleFileServlet

方案二:在Spring3.0.4以后版本提供了mvc:resources
<mvc:resources mapping="/images/**"   location="/images/"/>
/images/**映射到ResourceHttpRequestHandler进行处 理,location指定静态资源的位置.可以是web application根目录下、
jar包里面,这样可以把静态资源压缩到jar包中。cache-period 可以使得静态资源进行web cache 

如果出现下面的错误,可能是没有配置<mvc:annotation-driven />的原因。 
报错WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in 
DispatcherServlet with name 'springMVC'

使用<mvc:resources/>元素,把mapping的URI注册到SimpleUrlHandlerMapping的urlMap中,key为mapping的URI pattern值,
而value为ResourceHttpRequestHandler,这样就巧妙的把对静态资源的访问由HandlerMapping转到ResourceHttpRequestHandler
处理并返回,所以就支持classpath目录,jar包内静态资源的访问.另外需要注意的一点是,不要对SimpleUrlHandlerMapping设置
defaultHandler.因为对static uri的defaultHandler就是ResourceHttpRequestHandler,否则无法处理
static resources request.

方案三 :使用<mvc:default-servlet-handler/>
<mvc:default-servlet-handler/>
会把"/**" url,注册到SimpleUrlHandlerMapping的urlMap中,把对静态资源的访问由HandlerMapping转到
org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler 处理并返回.
DefaultServletHttpRequestHandler使用就是各个Servlet容器自己的默认Servlet.

多个HandlerMapping的执行顺序问题:
DefaultAnnotationHandlerMapping的order属性值是:0
<mvc:resources/ >自动注册的 SimpleUrlHandlerMapping的order属性值是: 2147483646
<mvc:default-servlet-handler/>自动注册 的SimpleUrlHandlerMapping 的order属性值是: 2147483647
spring会先执行order值比较小的。当访问一个a.jpg图片文件时,先通过 DefaultAnnotationHandlerMapping 来找处理器,
一定是找不到的,我们没有叫a.jpg的Action。再 按order值升序找,由于最后一个 SimpleUrlHandlerMapping 是匹配 "/**"的,
所以一定会匹配上,再响应图片。

五.Spring中的拦截器
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是下一个拦截器。

自定义的拦截器,要实现HandlerInterceptor接口
Spring MVC并没有总的拦截器,不能对所有的请求进行前后拦截。Spring MVC的拦截器,是属于HandlerMapping级别的,
可以有多个HandlerMapping ,每个HandlerMapping可以有自己的拦截器。当一个请求按Order值从小到大,顺序执行HandlerMapping接口的
实现类时,哪一个先有返回,那就可以结束了,后面的HandlerMapping就不走了,本道工序就完成了。就转到下一道工序了。拦截器会在什么时候执行呢?
一个请求交给一个HandlerMapping时,这个HandlerMapping先找有没有处理器来处理这个请求,如何找到了,就执行拦截器,执行完拦截后,交给目标
处理器。如果没有找到处理器,那么这个拦截器就不会被执行。
 
在spring mvc的配置文件中有三种配制方法
方案一:(近似)总拦截器,拦截所有url
<mvc:interceptors>
<bean class="com.app.mvc.MyInteceptor"/>
</mvc:interceptors>
为什么叫“近似”,前面说了,Spring没有总的拦截器
<mvc:interceptors/>会为每一 个HandlerMapping,注入一个拦截器。总有一个HandlerMapping是可以找到处理器的,
最多也只找到一个处理器,所以这个拦截器总会被执行的。起到了总拦截器的作用。
方案二:(近似) 总拦截器, 拦截匹配的URL。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.app.mvc.MyInteceptor"/>
</mvc:interceptor>
</mvc:interceptors>
比方案一多了一个url匹配
方案三:HandlerMapping上的拦截器
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">       
<property name="interceptors">       
    <list>       
        <bean class="com.mvc.MyInteceptor"></bean>      
    </list>       
</property>       
</bean>
如果使用 了<mvc:annotation-driven />, 它会自动注册DefaultAnnotationHandlerMapping 与AnnotationMethodHandlerAdapter
这两个bean,所以就没有机会再给它注入interceptors属性,就无法指定拦截器。当然我们可以通过人工配置上面的两个Bean,不使用 <mvc:annotation-driven />,
就可以 给interceptors属性 注入拦截器了。


  其实不建议使用<mvc:annotation-driven />,而建议手动写配置文件,来替代 <mvc:annotation-driven />,这就控制力就强了。   

六.实现全局的异常处理
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView">
<value>/error/error</value>
</property>
<property name="defaultStatusCode">
<value>500</value>
</property>
<property name="wranLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>  
</property>
</bean>
通过SimpleMappingExceptionResolver我们可以将不同的异常映射到不同的jsp页面(通过exceptionMappings属性的配置)。
同时我们也可以为所有的异常指定一个默认的异常提示页面(通过defaultErrorView属性的配置),如果所抛出的异常在exceptionMappings
中没有对应的映射,则Spring将用此默认配置显示异常信息。注意这里配置的异常显示界面均仅包括主文件名,至于文件路径和后缀已经在viewResolver中指定。
如/error/error表示/error/error.jsp


七、如何把全局异常记录到日志中
在前的配置中,其中有一个属性warnLogCategory,值是 “SimpleMappingExceptionResolver类的全限定名”。
我是在SimpleMappingExceptionResolver 类父类AbstractHandlerExceptionResolver类中找到这个属性的。
查看源码后得知:如果warnLogCategory不为 空,spring就会使用apache的org.apache.commons.logging.Log日志工具,记录这个异常,
级别是warn。值:“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”,
是“SimpleMappingExceptionResolver类的全限定名”。这个值不是随便写的。  因 为我在log4j的配置文件中还要加入
log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN, 
保证这个级别是warn的日志一定会被记录,即使log4j的根日志级别是ERROR。
 
八、转发与重定向
可以通过redirect/forward:url方法转到另一个Action进行连续的处理,可以通过redirect:url防止表单重复提交
return "forward:/order/add";
return "redirect:/index.jsp";


九、处理Ajax请求
1、引入下面两个包:
jackson-core-asl-1.7.2.jar 
jackson-mapper-asl-1.7.2.jar
2、spring的配置文件中要有<mvc:annotation-driven />,才能使用到spring内置支持的json转换。
如果你手工把POJO转成json就可以不须要使用spring内置支持的json转换。
3、使用@ResponseBody注解
@ResponseMapping("/ajax")
@ResponseBody
public Object ajax(HttpServletRequest request){
List<String> list=new ArrayList<String>();
list.add("电视");
list.add("冰箱");
return list;
}


十、例子
<1>.
@Controller
@RequestMapping("/user")
public class UserController{
private final UserService userService;

@Autowired
public UserController(UserService userService){
this.userService=userService;
}

@RequestMapping("/queryAll")
public String queryAll(@RequestParam("type") int type,Model model){
if(type==1){
List<User> userList=userService.findAll();
model.addAttribute("user",userList);
}
return "userList";  //返回页面
}
}

<2>.
//不返回页面,直接返回字符串或者io流,在方法上增加@ResponseBody标记
@RequestMapping("/queryAll2")
@ResponseBody
public String queryAll2(@RequestParam("type") int type){
JSONObject jsonObj=new JSONObject();
if(type==2){
List<User> users=userService.findAll();
jsonObj.put("users",users);
}
return jsonObj.toString();
}

<3>.
//表单数据绑定model,通过@ModelAttribute标记获取表单参数(需要Spring MVC所提供form tag库的支持)
@RequestMapping(value="/helloWrold",method=RequestMethod.POST)
public String helloWorld(@ModelAttribute User user){
return "helloWorld";
}

<4>.
//使用Session保存数据,要在控制器类上加上@SessionAttributes标记
@Controller
@RequestMapping("/user")
@SessionAttribute("user")
public class UserController{
private final UserService userService;

@Autowired
public UserController(UserService userService){
this.userService=userService;
}
}

<5>.
//上传jpg图片
@Controller
@RequestMapping("/upload")
public class FileUploadController implements ServletContextAware{
private ServletContext servletContext;

public void setServletContext(ServletContext servletContext){
this.servletContext=servletContext;
}

@RequestMapping("jpg")
public String uploadJPG(@RequestParam("image")MultipartFile image,Model model){
try{
if(!iamge.isEmpty()){
validateImage(image,"image/jpeg");
saveImage(image);
model.addAttribute("img","resources/upload"+File.separator+image.getName());
}
}catch(UploadImageException e){
model.addAttribute();
return "uploadError";
}
return "images";
}

private void saveImage(MultipartFile image) throws UploadImageException{
String name=image.getName();
try{
File file=new File(servletContext.getRealPath("/resources/upload")+File.separator+name);
FileUtils.writeByteArrayToFile(file,image.getBytes());
}catch(IOException e){
throw new UploadImageException("保存图片出错");
}
}

private void validateImage(MultipartFile image,String type)throws UploadImageException{
if(!image.getContextType().equals(type)){
throw  new UploadImageException("只接受JPG格式的文件!");
}
}
}

<6>.
@Controller
@Scope("prototype")
public class TestAction extends BaseCommonAction{
@RequestMapping(value="/test.do")
public String test(){
return "test";
}

@ReqeustMapping(value="/json.do")
public @ResponseBody Person json(){
return new Persion();
}
}

十一、配置过滤默认编码
<filter>
<filter-name>springCharacterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-calss>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springCharacterEncoding</filter-name>
<url-parttern>*.do</url-paratern>
</filter-mapping>






































































































0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 褐色分泌物流了好几天了怎么办? 淘宝买的衣服一直不发货怎么办 从国外寄东西到国内被税了怎么办 百度网盘上传文件数量有限制怎么办 腾讯视频上传文件过限制大小怎么办 三星s7打网页又卡又慢怎么办 路由器的上网账号和口令忘了怎么办 小米笔记本移动热点连接不上怎么办 移动宽带密码重置后认证失败怎么办 移动光纤不记得账号和密码怎么办? 宽带为什么交了钱还是不能用怎么办 小孩被虎牙直播诱导支付了款怎么办 房间里4g网络信号差怎么办 移动4g网络信号不满格怎么办 大风号无法上传视频暂停服务怎么办 过了竞牌保证金交付时间怎么办 亚马逊产品上架后货物没到怎么办 工行企业网银证书过期了怎么办 海淘转运地址国家填错了怎么办 集装箱实重与申报重量不一样怎么办 微博复制的淘口令找不到了怎么办 买了移动手机不能用联通卡怎么办 移动手机用联通卡网速慢怎么办 移动手机插联通卡没反应怎么办 移动手机办了联通大王卡怎么办 qq被冻结但是有至尊宝怎么办 qq被冻结了有至尊宝怎么办 移动电话卡注销了里面的钱怎么办 罗麦的oa上经理喜报没截图怎么办 工行融e联登录密码忘了怎么办 融e借有额度秒拒怎么办 工行银行柜台办理融e借怎么办 地球末日生存破解版金币没了怎么办 手机被别人骗走了里面的微信怎么办 在微信里面被做微商的骗了钱怎么办 在qq上骗了人50怎么办 被3m多酶清洗液滴到皮肤怎么办 做3m赔了9万怎么办 在携程网上订的酒店发票怎么办 滴滴滴取消订单电话打不通怎么办 百度云容量2068g满了怎么办