再探springMVC——01

再探springMVC——01

原创 無柳先生

1、SpringMVC的核心器件

1、DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、Handler:处理器(书写,即Controller)
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

4、HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

5、ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
6、View:视图(书写)
springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

2、SpringMVC运行流程

1、启动服务器,加载配置文件
  • DispatcherServlet 对象创建
  • springmvc.xml 配置文件被加载
  • HelloController 创建成对象
2、发送请求,后台处理请求,并展示结果

在这里插入图片描述

3、SpringMVC执行过程详解

SpringMVC框架基于组件方式执行流程

在这里插入图片描述

执行流程详解

  1. 发送请求(request)
  2. 前端控制器(dispatcherServlet)接受到请求,交给处理器映射器(handlerMapping),根据请求路径和方法上配置的path找到要执行的方法,并返回。
  3. 前端控制器(dispatcherServlet)接收到返回的结果后交给处理器适配器(HandlerAdapter)执行,处理器适配器使用适配器模式,可以对传过来的各种方法进行执行,返回ModelAndView对象。
  4. ModelAndView对象经过前端控制器的转发交给试图解析器,解析完毕后加上我们配置的前缀后后缀,返回view 对象,这时浏览器接收到后就可以进行解析和展示。
  5. 视图再经过前端控制器的转发响应给用户,便得到了我们的结果。

注意一点,在整个流程中都离不开前端控制器(dispatcherServlet),但是他的作用只是将任务进行分发。没有对接收的对象或者数据做任何的处理。

4、SpringMVC注解详解

1、@RequestMapping

@RequestMapping使用案例

@Controller
@RequestMapping("/user")
public class HelloController {
    @RequestMapping(value = "/hello" , method = RequestMethod.GET , params = "username" , headers = "Accept") //此时指定该方法只能接收get请求,并且请求中必须有username这个参数,在请求中必须有 Accept这个请求头
    public String hello(){
        System.out.println("hello , springMVC");
        return "success";
    }
}
2、@RequestMapping 源码分析
@Target({ElementType.METHOD, ElementType.TYPE}) //表示可以加在方法或者类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";
    @AliasFor("path") //取了个别名叫 path
    String[] value() default {};
    @AliasFor("value") //取了个别名叫 value
    //两个互相对应,表示两个属性的功能是相同的,都是指定url访问路径,value是默认的属性,如果只写这一个属性,那么value= 可以省略
    String[] path() default {};
    RequestMethod[] method() default {}; //指定请求的方式 ,RequestMethod是一个枚举类型,参数有:GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE 8种 
    String[] params() default {}; 
/*
	params属性用于指定限制请求参数的条件。它支持简单的表达式。要求参数的key和value必须和配置的一模一样。
	例如:params = {"accountName"},表示请求参数必须有accountName
		 params = {"money!100"},表示请求参数中的money不能是100
*/
    String[] headers() default {};//用于指定限制请求消息头的条件
    String[] consumes() default {};
    String[] produces() default {};
}

5、SpringMVC请求参数绑定

请求参数的绑定说明

1、绑定机制
  1. 表单提交的数据都是k=v格式的 username=haha&password=123
  2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
  3. 要求:提交表单的name和参数的名称是相同的
2、支持的数据类型
  1. 基本数据类型和字符串类型
  2. 实体类型(JavaBean)
  3. 集合数据类型(List、map集合等)
3、基本数据类型和字符串类型
  1. 提交表单的name和参数的名称是相同的
  2. 区分大小写
4、实体类型(JavaBean)
  1. 提交表单的name和JavaBean中的属性名称需要一致
  2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
5、给集合属性数据封装
  1. JSP页面编写方式:list[0].属性

复合参数传递实例

表单

      <form action="${pageContext.request.contextPath}/param/test01" method="get">
        用户名:<input type="text" name="username"/><br>
        密码:<input type="text" name="password"/><br>
        金额:<input type="text" name="money"/><br>
        姓名:<input type="text" name="user.name"/><br>
        年龄:<input type="text" name="user.age"/><br>
        <input type="submit" value="提交">
    </form>

实体类

public class Account {
    private String username;
    private String password;
    private double money;
    private User user;
    //省略get、set方法及toString方法		
}

public class User {
    private String name;
    private Integer age;
    //省略get、set方法及toString方法	
}

Controller

@Controller
@RequestMapping("/param")
public class ParamController {

    @RequestMapping(value = "/test01")
    public String testParam01(Account account){
        System.out.println("测试springMVC请求参数绑定");
        System.out.println(account);
        return "success";
    }
}

打印结果

测试springMVC请求参数绑定
Account{username='wuliuxs', password='ldyy122415', money=1000.0, user=User{name='lamoda', age=23}}

结论

SpringMVC 根据表单的name属性和方法的参数列表实现了对参数的自动封装 , 我们在传递时只需要注意name属性的值和我们实体类的属性名称是否对应。SpringMVC就可以实现对参数的自动封装,大大提高了开发的效率。

备注

如果是list和map集合进行数据的封装 , 那么使用 list[0].name 或 map[‘one’].name 进行封装即可,以下给出jsp及java代码。

<form action="account/updateAccount" method="post"> 
 	用户名称:<input type="text" name="username" ><br/>  
    用户密码:<input type="password" name="password" ><br/>  
    用户年龄:<input type="text" name="age" ><br/>  
    账户 1 名称:<input type="text" name="accounts[0].name" ><br/>  
    账户 1 金额:<input type="text" name="accounts[0].money" ><br/>  
    账户 2 名称:<input type="text" name="accounts[1].name" ><br/>  
    账户 2 金额:<input type="text" name="accounts[1].money" ><br/>  
    账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/>  
    账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/>  
    账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/>  
    账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/>  
    <input type="submit" value=" 保存 "> 
</form>
public class User implements Serializable {    
    private String username;  
    private String password;  
    private Integer age;  
    private List<Account> accounts;  
    private Map<String,Account> accountMap; 
}

请求参数中文乱码的解决

  1. 在web.xml中配置Spring提供的过滤器类

    <!--配置解决中文乱码的过滤器-->
        <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>
    

6、自定义类型转换器

  1. 表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。
  2. 如果想自定义数据类型转换,可以实现Converter的接口
public class StringToDateConverter implements Converter<String , Date> { //如果要自定义类型转换器,必须实现Conveter< S , T >接口,S为传入的String类型,T为你需要转换的类型。
    /**
     *  类型转换方法
     * @param source 传入的字符串
     * @return 返回一个转换完成的值
     */
    public Date convert(String source) {
        if ("".equals(source)){
            throw new NullPointerException();
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return df.parse(source);
        }catch (Exception e){
            e.printStackTrace();
            throw new ClassCastException();
        }
    }
}
  1. 注册自定义类型转换器,在springmvc.xml配置文件中编写配置
   <!--配置自定义类型转换器-->
    <bean id="conversionService1" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.ldyy.utils.StringToDateConverter"/>
            </set>
        </property>
    </bean>
    <!--开启springMVC注解支持-->
    <mvc:annotation-driven conversion-service="conversionService1"/>
  1. 在控制器中使用原生的ServletAPI对象

    1. 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

       @RequestMapping(value = "/servlet")
          public String testParam02(HttpServletRequest request , HttpServletResponse response){
              System.out.println("测试获取requset和response对象");
              System.out.println(request);
              System.out.println(response);
              System.out.println(request.getSession());
              return "success";
          }
      

6、常用的注解

1、@RequestParam

作用: 把请求中指定名称的参数给控制器中的形参赋值。

属性:

​ value:请求参数中的名称。

​ required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错

代码示例

@Controller
@RequestMapping("/annotation")
public class AnnotationController {
    @RequestMapping(value = "/test")
    public String test01(@RequestParam(name = "username") String name){
        System.out.println(name);
        return "success";
    }
}

@RequestParam注解源码

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean required() default true;

	String defaultValue() default ValueConstants.DEFAULT_NONE;

}
2、@ RequestBody

作用: 用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。

​ get 请求方式不适用。( get请求没有请求体 )

属性:

​ required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。

代码示例

@RequestMapping(value = "/test01")
    public String test01(@RequestBody String body){
        System.out.println(body);
        return "success";
    }
//输入为:  大熊  23  
//打印结果为: name=%E5%A4%A7%E7%86%8A&age=23

@ RequestBody 源码

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {

	boolean required() default true;

}
3、@ PathVaribale

作用: 用于绑定 url 中的占位符。

​ 例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。

​ url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

属性:

​ value:用于指定 url 中占位符名称。

​ required:是否必须提供占位符。

代码示例

@RequestMapping(value = "/test02/{id}")
    public String test02(@PathVariable("id") String id){
        System.out.println(id);
        return "success";
    }
//访问路径为: <a href="${pageContext.request.contextPath}/annotation/test02/12">PathVariable注解测试</a>
//打印结果为:12

@ PathVaribale 源码

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean required() default true;

}
@RequestHeader(一般不会用到,不做过多的介绍)

作用:

​ 用于获取请求消息头。

属性:

​ value:提供消息头名称

​ required:是否必须有此消息头

注: 在实际开发中一般不怎么用。

@CookieValue(一般不会用到,不做过多的介绍)

作用:

​ 用于把指定 cookie 名称的值传入控制器方法参数。

属性:

​ value:指定 cookie 的名称。

​ required:是否必须有此 cookie。

@ModelAttribute

作用:

​ 该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。

​ 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。

​ 它可以修饰没有返回值的方法,也可 以修饰有具体返回值的方法。

​ 出现在参数上,获取指定的数据给参数赋值。

属性:

​ value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。

应用场景:

​ 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。

例如:

​ 我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数 据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

代码示例 (@ModelAttribute修饰的方法有返回值)

@RequestMapping(value = "/test03")
public String test03(User user){
    System.out.println(user);
    return "success";
}
/**
* 说明:加上该注解的方法会在该执行的方法之前执行,可以帮助封装我们没有传递的参数,
* 他有两种情况 1、有返回值(如下) 2、没有返回值(可以使用一个map进行值的传递)
*/
@ModelAttribute
public User show(String name){
    User user = new User();
    user.setName(name);
    user.setBirthday(new Date());
    return user;
}

//访问路径为: 
<form action="${pageContext.request.contextPath}/annotation/test03" method="post">
    姓名:<input type="text" name="name"/><br>
    年龄:<input type="text" name="age"/><br>
    <input type="submit" value="提交">
</form>
//打印结果为:User{name='Java框架', age=23, birthday=Sat Oct 10 18:58:51 CST 2020}

代码示例 (@ModelAttribute修饰的方法无返回值)

@RequestMapping(value = "/test03")
public String test03(@ModelAttribute("abc") User user){
    System.out.println(user);
    return "success";
}
/**
* 说明:加上该注解的方法会在该执行的方法之前执行,可以帮助封装我们没有传递的参数,
* 	对于没有返回值的方法,我们可以使用map进行封装,传递一个map即可
*/
@ModelAttribute
public void show(String name , Map<String , User> map){
    User user = new User();
    user.setName(name);
    user.setBirthday(new Date());
    map.put("abc" , user);
}
//访问路径为: 
<form action="${pageContext.request.contextPath}/annotation/test03" method="post">
    姓名:<input type="text" name="name"/><br>
    年龄:<input type="text" name="age"/><br>
    <input type="submit" value="提交">
</form>
//打印结果为:User{name='java高级', age=34, birthday=Sat Oct 10 19:07:56 CST 2020}
@SessionAttribute

作用:

​ 用于多次执行控制器方法间的参数共享。

属性:

​ value:用于指定存入的属性名称

​ type:用于指定存入的数据类型。

代码示例

@Controller
@RequestMapping("/annotation")
@SessionAttributes("msg")
public class AnnotationController {
    //设置session
	@RequestMapping(value = "/setSession")
    public String setSession(Model model){
        model.addAttribute("msg" , "wuliuxs");
        return "success";
    }
    //获取session
    @RequestMapping(value = "/getSession")
    public String getSession(ModelMap modelMap){
        String msg = (String)modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }
    //删除session
    @RequestMapping(value = "/delSession")
    public String delSession(SessionStatus status){
        status.setComplete();//完成,清除session
        return "success";
    }
}
<a href="${pageContext.request.contextPath}/annotation/setSession">存入session</a> &nbsp;&nbsp;
<a href="${pageContext.request.contextPath}/annotation/getSession">获取session</a> &nbsp;&nbsp;
<a href="${pageContext.request.contextPath}/annotation/delSession">删除session</a>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值