SpringMVC--基础--注解(五)

一、@RequestMapping

通过 RequestMapping 注解可以定义不同的处理器映射规则。

二、 url 映射

定义 controller 方法对应的 url,进行处理器映射使用。

@RequestMapping(value="/user")或@RequestMapping("/user)

value 的值是数组,可以将多个 url 映射到同一个方法

  1. 窄化请求映射
    在 class 上添加@RequestMapping(url)指定通用请求前缀,限制此类下的所有方法请求 url 必
    须以请求前缀开头,通过此方法对 url 进行分类管理。
    如下:
// 放在类名上边,设置请求前缀
@RequestMapping 
@Controller
@RequestMapping("/user")

方法名上边设置请求映射 url:
@RequestMapping 放在方法名上边,如下:

@RequestMapping("/list")

访问地址为:/user/list

  1. 请求方法限定
    ◆ 限定 GET 方法
@RequestMapping(method = RequestMethod.GET)

如果通过 Post 访问则报错:

HTTP Status 405 - Request method 'POST' not supported

例如:

@RequestMapping(value="/user",method=RequestMethod.GET)

◆ 限定 POST 方法

@RequestMapping(method = RequestMethod.POST)

如果通过 GET 访问则报错:
HTTP Status 405 - Request method 'GET' not supported
◆ GET 和 POST 都可以

@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

三、 controller 方法的返回值

  1. 返回 ModelAndView
    controller 方法中定义 ModelAndView 对象并返回,对象中可添加 model 数据、指定view。
  2. 返回 void
    在 controller 方法形参上可以定义 request 和 response,使用 request 或 response 指定响应结果:
    A. 使用 request 转向页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);

B. 也可以通过 response 页面重定向:

response.sendRedirect("url")

C. 也可以通过 response 指定响应结果,例如响应 json 数据如下:

response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json 串");
  1. 返回字符串
    A. 逻辑视图名
    controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
//指定逻辑视图名,经过视图解析器解析为jsp物理路径:
/WEBINF/views/user/list.jsp
return "user/list";

B. Redirect 重定向
Contrller 方法返回结果重定向到一个 url 地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。

// 重定向到 list 地址,request 无法带过去
return "redirect:list";

redirect 方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的 request 和 response。
由于新发起一个 request 原来的参数在转发时就不能传递到下一个 url,如果要传参数可以/user/list 后边加参数,如下:

/user/list?...&…..

C. forward 转发
controller 方法执行后继续执行另一个 controller 方法。

// 结果转发到 list,request 可以带过去
return "forward:list";

forward 方式相当于

“request.getRequestDispatcher().forward(request,response)”

转发后浏览器地址栏还是原来的地址。转发并没有执行新的 request 和 response,而是和转发前的请求共用一个 request 和 response。所以转发前请求的参数在转发后仍然可以读取到。

四、参数绑定

处理器适配器在执行 Handler 之前需要把 http 请求的 key/value 数据绑定到 Handler 方法形参数上。
spring 参数绑定过程

  1. 默认支持的类型
    直接在 controller 方法形参上定义下边类型的对象,就可以使用这些对象。在参数绑定过程中,如果遇到下边类型直接进行绑定。
    A. HttpServletRequest
    通过 request 对象获取请求信息
    B. HttpServletResponse
    通过 response 处理响应信息
    C. HttpSession
    通过 session 对象得到 session 中存放的对象
    D. Model/ModelMap
    ✓ 控制器类:
@RequestMapping("/testUser")
public String testUser(Model model,ModelMap map){
model.addAttribute("user", "张三");
map.addAttribute("date", new Date());
return "userShow";
}

✓ 页面显示:

<body>
${user }
${date }
</body>

ModelMap 是 Model 接口的实现类,通过 Model 或 ModelMap 向页面传递数据,如下:

//调用 service 查询商品信息
Items item = itemService.findItemById(id);
model.addAttribute("item", item);

页面通过${item.XXXX}获取 item 对象的属性值。
使用 Model 和 ModelMap 的效果一样,如果直接使用 Model,springmvc 会实例化ModelMap。
注解适配器对 RequestMapping 标记的方法进行适配,对方法中的形参会进行参数绑定,早期 springmvc 采用 PropertyEditor(属性编辑器)进行参数绑定将 request 请求的参数绑定到方法形参上,3.X 之后 springmvc 就开始使用 Converter 进行参数绑定。

  1. 简单类型
    当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
    A. 整型
public String editItem(Model model,Integer id) throws Exception{
}

B. 字符串

public String editItem(Model model,String id) throws Exception{
}

C. 单精度/双精度

public String editItem(Model model,Float id) throws Exception{
}

D. 布尔型

public String editItem(Model model,Boolean id) throws Exception{
}

处理器方法:

public String editItem(Model model,Integer id,Boolean status) throws Exception

请求 url:

http://localhost:8080/springmvc_mybatis/item/editItem.action?id=2&status=false

说明:对于布尔类型的参数,请求的参数值为 true 或 false。
E. 使用@RequestParam 常用于处理简单类型的绑定。
value:参数名字,即入参的请求参数名字,如 value=“itemid”表示请求的参数区中的名字为 itemid 的参数的值将传入;
required:是否必须,默认是 true,表示请求中一定要有相应的参数,否则将报;
TTP Status 400 - Required Integer parameter 'XXXX' is not present
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
定义如下:

public String editItem(@RequestParam(value="item_id",required=true) String id) {
}

形参名称为 id,但是这里使用 value=" itemid"限定请求的参数名为 itemid,所以页面传递参数的名必须为 itemid。
注意:如果请求参数中没有 item_id 将跑出异常:
HTTP Status 500 - Required Integer parameter 'itemid' is not present
这里通过 required=true 限定 itemid 参数为必需传递,如果不传递则报 400 错误,可以使用 defaultvalue 设置默认值,即使 required=true 也可以不传 itemid 参数值。

  1. pojo绑定
    将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
    A. 页面定义如下;
<input type="text" name="name"/>
<input type="text" name="price"/>

B. Contrller方法定义如下:

@RequestMapping("/editItemSubmit")
    public String editItemSubmit(Items items)throws Exception{
    System.out.println(items);
}

请求的参数名称和pojo的属性名称一致,会自动将请求参数赋值给pojo的属性。

  1. 包装pojo
    如果采用类似struts中对象.属性的方式命名,需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
    A. 包装对象定义如下:
Public class QueryVo {
private Items items;
}

B. 页面定义:
<input type="text" name="items.name" />
<input type="text" name="items.price" />
C. Controller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getItems());
}
  1. 自定义参数绑定
    根据业务需求自定义日期格式进行参数绑定。
    A. 自定义Converter
public class CustomDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return simpleDateFormat.parse(source);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

B. 配置方式1

    <mvc:annotation-driven conversion-service="conversionService">
    </mvc:annotation-driven>
    <!-- conversionService -->
    <bean id="conversionService"
    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <bean class="com.neuedu.converter.CustomDateConverter" />
            </list>
        </property>
    </bean>

C. 配置方式2

   <!-- 注解映射器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!--注解适配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="webBindingInitializer" ref="customBinder"></property>
    </bean>

    <!-- 自定义webBinder -->
    <bean id="customBinder"
          class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
        <property name="conversionService" ref="conversionService"/>
    </bean>
    <!--注解适配器 -->
    <bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <bean class="com.neuedu.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>

说明:
与配置方式1相同,只不过是手动加载映射器与适配器。

D. 实体类中加日期格式化注解

@DateTimeFormat(pattern = "yyyy-MM-dd")  
private Date receiveAppTime;

使用注解,一定要去掉原有添加的自定义时间转换器,否则两个冲突。
E、页面把日期类型转换成字符串JSP:
如果是JSON格式,一定要加以下注解。

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
或
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>   
<fmt:formatDate value="${job.jobtime }" pattern="yyyy-MM-dd HH:mm:ss"/>  

虽然时间格式正确了,但早了8小时,因为,jackson在序列化时间时是按照国际标准时间GMT进行格式化的,而在国内默认时区使用的是CST时区,两者相差8小时。

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

因为 @JsonFormat 注解不是 Spring 自带的注解,所以使用该注解前需要添加 jackson 相关的依赖包。当然,如果是 SpringBoot 项目就不需要自己手动添加依赖了,因为在 spring-boot-start-web 下已经包含了 jackson 相关依赖。

        <!--spring mvc-json依赖-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.9</version>
        </dependency>

总结:
注解@JsonFormat主要是后台到前台的时间格式的转换
注解@DataFormAT主要是前后到后台的时间格式的转换

  1. 集合类
    A. 字符串数组
    页面定义如下:
    页面选中多个checkbox向controller方法传递
<input type="checkbox" name="itemid" value="001"/>
<input type="checkbox" name=" itemid" value="002"/>
<input type="checkbox" name="itemid" value="002"/>

传递到controller方法中的格式是:001,002,003

Controller方法中可以用String[]接收,定义如下:
public String deleteitem(String[] itemid)throws Exception{
        System.out.println(itemid);
}

B. List
List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。
List中对象:

Public class QueryVo {
Private List<Items> itemList;  // 商品列表
  //get/set方法..
}

包装类中定义List对象,并添加get/set方法如下:
页面定义如下:

    <tr>
        <td><input type="text" name=" itemsList[0].id" value="${item.id}" />
        </td>
        <td><input type="text" name=" itemsList[0].name"
            value="${item.name }" /></td>
        <td><input type="text" name=" itemsList[0].price"
            value="${item.price}" /></td>
    </tr>
    <tr>
        <td><input type="text" name=" itemsList[1].id" value="${item.id}" />
        </td>
        <td><input type="text" name=" itemsList[1].name"
            value="${item.name }" /></td>
        <td><input type="text" name=" itemsList[1].price"
            value="${item.price}" /></td>
    </tr>

上边的静态代码改为动态jsp代码如下:

<c:forEach items="${itemsList }" var="item" varStatus="s">
<tr>
    <td><input type="text" name="itemsList[${s.index }].name" value="${item.name }"/></td>
    <td><input type="text" name="itemsList[${s.index }].price" value="${item.price }"/></td>
    .....
    .....
</tr>
</c:forEach>

Contrller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getItemList());
}

C. Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:

Public class QueryVo {
    private Map<String, Object> itemInfo = new HashMap<String, Object>();
      //get/set方法..
    }

页面定义如下:

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text" name="itemInfo['name']"/>
年龄:<inputtype="text" name="itemInfo['price']"/>
</td>
</tr>

Contrller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

五、JSON数据

1. 请求参数添加注解:@RequestBody

  public RequestUser userJson(@RequestBody RequestUser requestUser) {}

2. 如果获取响应数据添加注解: @ResponseBody

@ResponseBody
public RequestUser userJson(@RequestBody RequestUser requestUser) {}

或:

public @ResponseBody RequestUser userJson(@RequestBody RequestUser requestUser) {

六、常用注解

注解 说明
@Controller 用于标识是处理器类;
@RequestMapping 请求到处理器功能方法的映射规则;
@RequestParam 请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute 请求参数到命令对象的绑定;
@SessionAttributes 用于声明 session 级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到 session 中;
@InitBinder 自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
@CookieValue cookie 数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader 请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody 请求的 body 体的绑定(通过 httpMessageConverter 进行类型转换);
@ResponseBody 处理器功能处理方法的返回值作为响应体(通过

HttpMessageConverter 进行类型转换);
@ResponseStatus |定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler |注解式声明异常处理器;
@PathVariable | 请求 URI 中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持 RESTful 架构风格

六、常见错误:

  1. 严重: Unable to process Jar entry [module-info.class] from Jar [jar:file:/d:/.m2/org/ow2/asm/asm/7.1/asm-7.1.jar!/] for annotations
    解决:
    无法从Jar包[****]中处理Jar条目[module-info.class],而module-info.class用记事本打开后可以看到其内容,而且在实际项目中,module-info.java经常用来处理模块之间的依赖关系等,可选择直接删除。


    删除module-info.class
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容