spring-mvc

springmvc

DispatcherServlet:前端控制器

概念:spring在web层的一个mvc架构的框架
作用:
处理用户请求与相应
渲染视图

特点:
清晰的角色划分,各司其职
可定制的映射器,处理器
灵活的model转换
spring标签库

功能:请求、响应、模型、视图

快速入门
导包

 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
</dependency>
 <dependency>
      groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
</dependency>

1、web.xml配置前端控制器

<servlet>
    <servlet-name>dispatherServlet</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>
</servlet>

<servlet-mapping>
    <servlet-name>dispatherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

2、编写springmvc.xml

<context:component-scan base-package="com.springmvc.controller"/>

3、编写Controller

@Controller
public class UserController {
// login这个处理器与url进行绑定
@RequestMapping("login")
public ModelAndView login(Integer username) {
    ModelAndView mav = new ModelAndView();
    mav.addObject("user", username);// model,相当于将数据放到request域对象中
    mav.setViewName("user.jsp");// view
    return mav;
}

}

springMVC大致原理


Some_Text

以下组件通常使用框架提供实现:
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器

HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器

Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
HandlAdapter:处理器适配器

通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver:视图解析器

View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
View:视图

springmvc框架提供了很多的View视图类型的支持,包括:jstl、freemarker、pdf等。我们最常用的视图就是jsp。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
说明:在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。 需要用户实现的组件有handler、view

springMVC原理在代码中的体现


Some_Text

1、根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法)
2、然后匹配路径对应的拦截器
3、通过HandlerMapping接口实现类获得HandlerExecutionChain对象(包含HandlerMethod和拦截器)
4、有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到ModelAndView对象
调用HandlerMethod内部handle的时候:
1、使用各种HandlerMethodArgumentResolver接口实现类,完成参数绑定2、使用到各种Converter接口实现类,完成类型转换3、使用各种HandlerMethodReturnValueHandler接口实现类,处理返回值4、最终返回值被处理成ModelAndView对象5、这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理

5、RequestToViewNameTranslator接口实现类将请求地址解析为视图名(若有手动设置视图名,则使用手动设置的)
6、通过各种View和ViewResolver接口实现类渲染视图(将Model中的数据放到request域对象中,页面的编译。。。)

非注解方式配置springMVC
在DispatherServlet.propterties文件中
HandlerMapping= BeanNameUrlHandlerMapping, DefaultAnnotationHandlerMapping(该类已过期)
HandlerAdapter= HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter, AnnotationMethodHandlerAdapter(该类已过期)
HandlerExceptionResolver= AnnotationMethodHandlerExceptionResolver, ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver
RequestToViewNameTranslator= DefaultRequestToViewNameTranslator
ViewResolver= InternalResourceViewResolver
FlashMapManager= SessionFlashMapManager

开启注解扫描的方式配置springMVC

<mvc:annotation-driven />

作用:
创建RequestMappingHandlerMapping
创建RequestMappingHandlerAdapter
注册Converter的各种实现类,例如json转换,日期格式转换等

1、RequestMappingHandlerMapping
作用:注解式处理器映射器,对类中标记@ResquestMapping的方法进行映射,根据ResquestMapping定义的url匹配ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器,HandlerMethod对象中封装url对应的方法Method。
注意:从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。
配置如下:

<bean 
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

2、RequestMappingHandlerAdapter
作用:注解式处理器适配器,对标记@ResquestMapping的方法进行适配。
注意:从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
配置如下:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

视图与模型

视图
springmvc.xml配置

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

 //返回的字符串就是视图名称,提前是在springmvc.xml中配置了后缀名
@RequestMapping("view1")
public String view1(){
    return "formString";
}
//如果返回返回值,那么默认视图名为请求地址(约定优于配置原则)
@RequestMapping("formString")
public void view2(){}

模型数据

//Model的本质就是map集合,视图解析器会将Model中的数据放到request域对象中

//原始的写法,使用ModelAndView
@RequestMapping("model1")
public ModelAndView model1(){
    ModelAndView mav=new ModelAndView();
    mav.addObject("user", new User("lisi","123"));
    mav.setViewName("model1");//如果这句不写,那么使用约定的视图名
    return mav;
}
//简化了上面的写法
@RequestMapping("model2")
public String model2(Model model){
    model.addAttribute("username",  new User("lisi","123"));
    return "model1";
}
//再简化了上面的写法,如果没有返回视图名,那么默认使用请求地址作为视图名
@RequestMapping("model3")
public void model3(Model model){
    model.addAttribute("user",  new User("lisi","123"));
}

//------------------综合--------------------
@RequestMapping("model4")
public void model4(Model model,User user){
    //将user添加到Model中
    model.addAttribute("user", user);
}
//简化上面的写法
@RequestMapping("model5")
public void model5(@ModelAttribute User user){//直接将参数绑定好后的user添加到Model中
}   
@ModelAttribute("user")
//将返回值暴露为模型数据,因为没有@RequestMapping注解,所以该方法不是处理器,它在每个处理器之前执行
public User getUser(){
    return new User("zhangsan", "123");
}

请求与响应

参数绑定
可以被注入的类型: HttpServletRequest, HttpServletResponse, HttpSession, Principal, Locale, InputStream, Reader, OutputStream, Writer, String, StringBuffer, Pojo, Date, List, Map, Array, Model, ModelMap等等

转换服务
转换服务为参数绑定时,处理数据类型的转换。
DefaultConversionService:默认的类型转换服务实现
DefaultFormattingConversionService:带数据格式化支持的类型转换服务实现,一般使用该服务实现即可。
springmvc在开启注解驱动,注册了很多Converter的实现类,但是如果不能满足需求,可以自定义转换器。具体如下:

//实现Converter接口

public class MyDateConverter implements Converter<String, Date>{

//重写convert方法
@Override
public Date convert(String str) {
    SimpleDateFormat sdf=null;
    //java正则表达式不用写/开头和结尾,js中需要
    Pattern pattern1=Pattern.compile("^\\d{4}年\\d{1,2}月\\d{1,2}日$");
    Pattern pattern2=Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
    Pattern pattern3=Pattern.compile("^\\d{4}/\\d{2}/\\d{2}$");
    try {
        if(pattern1.matcher(str).matches()){
             sdf=new SimpleDateFormat("yyyy年MM月dd日");
             return sdf.parse(str);
        }
        if(pattern2.matcher(str).matches()){
             sdf=new SimpleDateFormat("yyyy-MM-dd");
             return sdf.parse(str);
        }
        if(pattern3.matcher(str).matches()){
             sdf=new SimpleDateFormat("yyyy/MM/dd");
             return sdf.parse(str);
        }

        //或者下面的写法
        /*if(str.matches("^\\d{4}年\\d{2}月\\d{2}日$")){
            sdf=new SimpleDateFormat("yyyy年MM月dd日");
            return sdf.parse(str);
        }
        if(str.matches("^\\d{4}-\\d{2}-\\d{2}$")){
            sdf=new SimpleDateFormat("yyyy-MM-dd");
            return sdf.parse(str);
        }
        if(str.matches("^\\d{4}/\\d{2}/\\d{2}$")){
            sdf=new SimpleDateFormat("yyyy/MM/dd");
            return sdf.parse(str);
        }*/
    } catch (Exception e) {
        e.printStackTrace();
    }   
    return null;
}

}
将自定义的转换器添加到springmvc转换服务中

 <mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.hemi.controller.converter.MyDateConverter"/>   
        </list>
    </property>
</bean>

注意: 1、如果是单纯的日期格式转换可以使用@DateTimeFormat来实现

 @DateTimeFormat(pattern="yyyy年MM月dd日")//写了该注解,默认的yyyy/MM/dd hh:mm:ss的格式就无法使用了
private Date date;  

2、上面的转换只能处理url参数和请求体参数,如果是json中的日期格式转换,请使用@JsonFormat注解,请看下面的json部分。

json
导包
1 将json-->bean
2 将bean-->json

 <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.1</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.1</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.1</version>
    </dependency>

1、json数据发送
后台:
1、@RequestBody
2、jackson的3个jar包

@RequestMapping("jsonToBean")
@ResponseBody //返回的对象封装成json
public User jsonToBean(@RequestBody User user){//@RequestBody将请求的json封装成对象
    return user;
}

前台:
1、contentType:appliation/json;charset=utf-8
2、JSON.stringify(json),

 var json={username:"lisi",password:"123"};//定义json对象

$(function(){
    $("#btn").click(function(){
        $.ajax({
            url:"/springmvc/jsonToBean",
            type:"post",
            contentType:"application/json;charset=utf-8",
            //js原生的一个将json对象转成json字符串的工具类           
            data:JSON.stringify(json),
            dataType:"text",
            success:function(data){
                $("#content").html(data);
            }
        });
    });
});

2、解决json日期格式化问题

 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date date;

3、解决json写入@ResponseBody后出现中文乱码的问题

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <!--解决返回json乱码-->
                    <value>application/json;charset=UTF-8</value>
                    <!--解决返回字符串乱码-->
                    <value>text/html;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
    <!--或者下面这种方式-->
    <!-- <mvc:message-converters register-defaults="true">
        <bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json;charset=UTF-8</value>
                    <value>text/html;charset=UTF-8</value>
                </list>
            </property>
        </bean>
     </mvc:message-converters> --> 
</mvc:annotation-driven>

4、json其他常用的注解

@JsonInclude(JsonInclude.Include.NON_NULL)//当属性为null的时候,就不序列该属性,不为null就序列化

public class User {
@JsonIgnore //忽略某个属性,不要被json序列化
private Integer id;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date date;

}

文件上传下载

文件上传

1、基本步骤

1、handler参数添加@RequestParam MultipartFile multipart

//name指的是<input name=""> 注意:不能是驼峰命名,必须都是小写
@RequestParam(name="user_photo",required=false) MultipartFile multipart

2、调用MultipartFile的transforTo(file)的方法,将文件写入到本地
3、springmvc.xml文件配制CommonsMultipartResolver视图

 <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="5000000" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>

4、上传文件的jsp


Some_Text

2、注意问题
上传文件的路径

  String path = req.getServletContext().getRealPath("statics" + File.separator + "uploadfile");

如果项目没有发布到tomcat服务器中,那么默认是在eclipse的对应项目目录中,这样导致图片找不到路径
解决方法:
1、将项目发布到tomcat,但是每次重新加载项目或者重启服务器就会删除已上传的文件
2、上传到一个统一的文件夹,项目引用该文件夹下的文件,这样不会被迫删除已有文件

 <Context path="/statics" docBase="E:/download" reloadable="true" crossContext="true" />

<param-name>listings</param-name><param-value>true</param-value>

3、上传到其他http服务器上,例如nginx服务器,推荐!

文件下载
服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器中显示,如果需要提示用户保存,就要利用Content-Disposition进行一下处理,关键在于一定要加上attachment
Content-Disposition为属性名,计划安排之意
attachment:附件方式下载
filename为默认保存时的文件名

resp.setContentType("application/force-download");
resp.addHeader("Content-Disposition", "attachment;filename=" + filename);byte[] byteArray = 
FileUtils.readFileToByteArray(file);resp.getOutputStream().write(byteArray);

配置静态资源文件访问
方式一:

<mvc:resources location="/statics/" mapping="/statics/**">
</mvc:resources>

方式二:使用servlet容器默认的DefaultServlet

 <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>

方式三:原理与方式二一致

<mvc:default-servlet-handler />

拦截器
自定义拦截器,实现HandlerInterceptor接口,并重写三个方法

public class MyInterceptor implements HandlerInterceptor {
preHandle(){}//执行Handler之前,返回true,则继续进行,返回false则中断请求
postHandle(){}//执行Handler时
afterCompletion(){}//执行Handler之后

}
将自定义拦截器,添加到springmvc的拦截体系中

 <mvc:interceptors>
    <mvc:interceptor>
        <!--拦截器的请求-->
        <mvc:mapping path="/**"/>
        <!--放行的请求,即公开的地址-->
        <mvc:exclude-mapping path="/login/**"/>
        <bean class="com.hemi.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

多个拦截器执行顺序

Some_Text

Some_Text

只要preHandler()返回true,那么afterCompletion()就会执行
三个拦截器,如果preC返回fales,那么最终执行的是preA-->preB-->preC-->afterB-->afterA
使用详细说明

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 1.Spring web mvc介绍 Spring web mvc和Struts2都属于表现层的框架,它是Spri...
    七弦桐语阅读 11,509评论 2 38
  • 1、Spring MVC请求流程 (1)初始化:(对DispatcherServlet和ContextLoderL...
    拾壹北阅读 1,946评论 0 12
  • Spring mvc 框架 DispatcherServlet前端控制器 ---- 整个流程控制的中心,由它调用其...
    蕊er阅读 693评论 0 0
  • Spring MVC一、什么是 Spring MVCSpring MVC 属于 SpringFrameWork 的...
    任任任任师艳阅读 3,374评论 0 32
  • 前言 对于Spring MVC项目搭建相信大家按照网上教程来做基本都会,但更多时候我们应该多问几个为什么,多思考实...
    九风萍舟阅读 2,741评论 0 12