SpringMVC配置和注解说明

image.png

SpringMVC配置

入门案例-环境配置

  1. 创建maven-webapp项目,如下图所示
image-20200207103227886.png
  1. 在属性配置界面添加一对key-value,用于避免自动下载一大堆插件,因为会很慢

    key: archetypeCatalog
    value: internal

image-20200207103351484.png
  1. 自己配好文件夹

    image-20200207104033152.png
  1. 导入依赖包
  • spring-context是spring的核心框架

  • spring-web和spring-webmvc用于支持springMVC框架和web应用

  • javax.servlet-api和jsp-api用于支持servlet和jsp

  • junit用于支持单元测试,方便测试的时候使用


  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.26.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.26.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.26.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
    </dependency>


  </dependencies>
  1. 建立springmvc配置文件springmvc.xml,并导入约束。此处需要导入两个命名空间,一个是 xmlns:context用于支持spring注解,xmlns:mvc用于支持springmvc注解

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    </beans>
    
  2. web.xml配置servlet拦截

    然后为了让我们写的springmvc.xml被识别到,需要指出它在哪。于是我们用<init-param>去说明。
    配置filter是为了配置编码为UTF-8。所有的请求过来都会用UTF-8去解码。

  <!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <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>


  <servlet>
    <servlet-name>dispatcherServlet</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的启动顺序-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

入门案例-编写代码

  1. 建立index.jsp页面,包含链接<a href="hello">click</a>,指向hello路径(相对路径)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>hello</title>
    </head>
    <body>
    <h1>hello SpringMVC</h1>
    <a href="hello">click</a>
    
    </body>
    </html>
    
  2. 编写Controller类HelloController

    • @Controller是spring的注解,用于注册Bean,与 @Component,@Service, @Repositry作用相同。为了区分这是个控制器而用了它。
    • @RequestMapping("/hello")用于指定匹配的url,这里url为"/hello",需要包含 /
    • 要求有@RequestMapping注解的方法返回值是String或者ModelAndView,这里先写String。返回值是要跳转的页面名称,这个要结合后面视图解析器来用
    package com.chajiu.contorller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HelloController {
    
        @RequestMapping("/hello")
        public String sayHello(){
            System.out.println("hello SpringMVC");
            return "success";
        }
    }
    
  3. 编写要跳转的页面success.jsp

    位置:在/WEB-INF/pages/下面,要和后面配置视图解析器对应

image-20200207105101463.png
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h1>success!</h1>
</body>
</html>

  1. 配置springmvc.xml

    @RequestMapping注解的方法返回的String都会先到视图解析器里,把前缀后缀加上,拼接成完整的要跳转的页面的路径,再去访问。

     <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启spring注解支持,让spring扫描包-->
    <context:component-scan base-package="com.chajiu.contorller"></context:component-scan>
    <!--开启SpringMVC注解的支持-->
    <mvc:annotation-driven/>
    
    <!--配置视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>
    </beans>
    

入门案例-启动

配好tomcat,启动,发现成功跳转。

@RequestMapping注解

用于匹配url。

类上也可以用它,表示一级拦截方式,方法上是二级拦截。

比如类上有@RequestMapping("/usr"),方法上有@RequestMapping("/hello"),那么只有"/usr/hello"的请求才能进入该方法。

属性:

  • value:等同path,用于指定请求的url

  • path:等同value

  • method:规定接受url的请求方式,取值有

    GET,用于查询
    HEAD,
    POST,用于增
    PUT,用于更新
    PATCH,用于更新
    DELETE,用于删除
    OPTIONS,
    TRACE;
    
    
  • params:用于规定上传的参数必须包含指定的key

    @RequestMapping(path = "/hello",params = {"username","password"})
    

请求参数绑定

1. 基本数据类型

url:

hello?username=ccc&password=123

方法:

@RequestMapping("/hello")
public String getAccount(String username, String password){...}

属性名称和形参名称对应即可。

2. pojo类型

public class Account {
    private Integer id;
    private String username;
    private String password;
    //getter
    //setter

如何注入Account?

提交的属性名和Account里属性名对应即可,方法参数直接写Account。如果没对上,则对应属性为null

<form action="param/saveAccount">
    username:<input  type="text" name="username"><br>
    password:<input type="text" name="password"><br>
    <input type="submit" value="submit">
</form>


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

    @RequestMapping("/saveAccount")
    public String saveAccount(Account account){
        System.out.println(account);
        return "success";
    }
}

pojo里包含引用类型怎么办

public class Account {
    private Integer id;
    private String username;
    private String password;
    <!--多了个user-->
    private User user;

映射方法不变,jsp中修改input的name:

<form action="param/saveAccount">
    username:<input  type="text" name="username"><br>
    password:<input type="text" name="password"><br>
    name:<input type="text" name="user.name"><br>
    age:<input type="text" name="user.age"><br>
    <input type="submit" value="submit">
</form>

怀疑这个请求参数绑定的方式应该是形参的Bean加上提交的属性名,组成全限定类名再注入。

因此注入Account的User的name就要是com.chajiu.pojo.Accout.user.name,因此html中要写user.name

3. 集合类型

比如User有个List集合:

public class User {
    private Integer id;
    private String name;
    private Integer age;

    private List<Role> roles;

jsp要上传User数据,同时包含多个角色信息,那怎么办?

在name那做文章:

<form action="param/saveUser" method="post">
    name:<input  type="text" name="name"><br>
    age:<input type="text" name="age"><br>
    role:<input type="text" name="roles[0].role"><br>
    <input type="submit" value="submit">
</form>

使用集合的属性名[i].子属性名表示。List中第一个role是roles[0].roleName,那么第二个role就是roles[1].roleName

如果是Map怎么表示?

role["key"].roleName

自定义类型转换器

提交数据都是字符串,如何会封装到Integerdouble?springMVC有转换器会帮我们把常见的数据类型进行转换再存入pojo中。

但是有时候这种转换不是我们想要的效果。比如String到Date,他给的转换只能转1998/12/28这种类型,对于1998-12-28将无能为力,报错。

所以我们有时候需要自定义类型转换器。

自定义一个类,实现Convert<s,t>接口:

public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        if (s==null)
            throw new RuntimeException("请输入数据");
        DateFormat dateFormat=new SimpleDateFormat("yyyy-mm-dd");
        try {
            return dateFormat.parse(s);
        } catch (Exception e) {
            throw new RuntimeException("输入格式有误");
        }

    }
}

修改springmvc.xml:

  • 定义ConversionServiceFactoryBean的bean,并把你自己写的转换器注入converters这个set集合中。
  • 让mvc使用你这个ConversionServiceFactoryBean
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.chajiu.converter.StringToDateConverter"></bean>
        </set>
    </property>
</bean>

 <!--    添加conversion-service,指向自己的转换器bean-->
    <mvc:annotation-driven conversion-service="conversionService"/>

但是在修改后,只支持1998-12-28了。哈哈哈

拿到Servlet原生API

如何在方法中拿到request和response呢?

只要在你的方法形参中加入他们,springmvc在调用这个方法时就会自动绑定进去。

@RequestMapping("/saveUser")
public String savesUser(User user, HttpServletRequest req, HttpServletResponse res){
    System.out.println(user);
    System.out.println(req);
    System.out.println(res);
    HttpSession session = req.getSession();
    System.out.println(session);
    return "success";
}

常用注解

RequestParam

情况1:请求属性名和方法形参名对不上就没法匹配了吗?

比如你的url是 /user?name=aaa,而方法形参为 String username

正常情况无法匹配,但是我们可以手动修改映射关系:

@RequestMapping("/requestParam")
public String testRequestParam(@RequestParam(name="name") String username){

意为让请求中的name去匹配username

同时我们看出该注解只能修改基本类型的映射关系。对于pojo实体类无法起作用。

RequestBody

用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。
get 请求方式不适用。

@RequestMapping("/requestBody")
public String testRequestBody(String username,@RequestBody String body){

PathVaribale

用于绑定占位符和形参,{sid}为占位符。

使用占位符可以匹配多种url。特别是在RESTful风格的开发中,类似 /pathVariable/10,/pathVariable/12都会匹配到该方法。

@RequestMapping("/pathVariable/{sid}")
public String testPathVariable(@PathVariable(name="sid") String id){

RequestHeader

获取指定请求头部,比如我想获取Accept头部信息:

@RequestMapping("/requestHeader")
public String testRequestMapping(@RequestHeader("Accept") String accept){

CookieValue

用于获得指定的cookie值.

同样是绑定到某个形参上使用

@RequestMapping("/cookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String jsessionid){

ModelAttribute

给model添加属性的。在执行所有控制方法前先执行。

应用场景:要在控制方法执行前对请求参数做某些操作,比如修改值,填充null。

两种使用方式:

  • 修饰方法
  • 修饰形参

修饰方法:

  • 方法有返回值时,据说自动会把返回值作为value,小写类名作为key放入modelMap中,也就是放入requestScope中。
  • 也可以@ModelAttribute(value="abc")来指定key为abc
@ModelAttribute
public Account show(String username,String password){
   Account account=new Account();
   account.setId(1);
   account.setUsername(username);
   account.setPassword(password);
   return account;
}
  • 方法没返回值时,要放入需要先显式地绑定modelMap,然后用put方法自己放进去

    @ModelAttribute
    public void show(String username, String password, Map<String , Account> accountMap){
        Account account=new Account();
        account.setId(1);
        account.setUsername(username);
        account.setPassword(password);
        
        accountMap.put("acco",account);
    }
    

至于这里为什么声明了一个Map呢?因为modelMap是他实现类。接口 指向实现类是可以的。下面请看关系图:

image-20200208160549277.png

可以看出其实modelMap其实就是个Map,里面可以存放键值对。

修饰形参:

  • 从modelMap中取value给形参赋值

  • 下面就把acco对应的对象和形参account绑定了

    @RequestMapping("/modelAttribute")
    public String testModelAttribute(@ModelAttribute("acco") Account account){
        System.out.println(account);
        return "success";
    }
    

SessionAttributes

为了减少耦合,所以在把键值对放入requestScope中时,我们没有直接用元素的ServletAPI,而是用了一个中间对象ModelMap,把键值对交给他,他自动会存入RequestScope中。

那么如何不直接操作Session而把键值对放入SessionScope中呢?

使用SessionAttributes注解,会把modelMap中指定的键值对放入SessionScope中。

需要在类上使用:

@Controller
@SessionAttributes(value={"username"})
@RequestMapping("/anno")
public class AnnoController {

会把modelMap中key为username的属性放入SessionScope。当然可以指定多个。

方法中获取SessionScope中的对象:

  • 使用ModelMap的get方法。
  • 这个方法也能从requestScope中获取对象。
@RequestMapping("/getSessionAttribute")
public String getSessionAttribute(ModelMap modelMap){
    String uname= (String) modelMap.get("username");
    System.out.println(uname);
    return "sessionAttributePage";
}

其实我感觉,SpringMVC把jsp的四大作用域都封装在了ModelMap中。所以用ModelMap.get()方法应该也是从四大域中取值。只是查找的顺序不同。从而避免我们之间操作四大域,减少耦合。

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

推荐阅读更多精彩内容