九点钟☆方向

记录成长点滴

欢迎来到我的个人博客~


SpringMVC笔记(二) SpringMVC参数绑定和响应数据结果视图

目录

参数绑定

作用:接受client提交的数据

支持的数据类型

基本类型参数:包括基本类型和 String 类型

POJO 类型参数:包括实体类,以及关联的实体类

数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)

示例

使用原生的ServletAPI对象

只需要在控制器的方法中将servletApi对象当作参数传入即可

@RequestMapping(value = "/converter1",method = RequestMethod.POST)
public void converter1(HttpServletRequest request) {
    String username = request.getParameter("username");
    String age = request.getParameter("age");
    String birthDay = request.getParameter("birthDay");
    System.out.println(username + "----" + age + "----" + birthDay);
}

springmvc支持传入的Sevlet原生api一共有以下这些 
1. HttpServletRequest 
2. HttpServletResponse 
3. HttpSession 
4. java.security.Principal 
5. Locale 
6. InputStream 
7. OutputStream 
8. Reader 
9. Writer

基本数据类型+String

要求参数名称必须和控制器中方法的形参名称保持一致。 (严格区分大小写)

//jsp 代码:
<a href="account/findAccount?accountId=10&accountName=zhangsan">查询账户</a>

控制器代码
@RequestMapping("/findAccount")
public String findAccount(Integer accountId,String accountName) {
    System.out.println("查询了账户。。。。 "+accountId+","+accountName);
    return "success";
}

POJO 类型作为参数

要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。

jsp 代码:
<form action="account/saveAccount" method="post">
    账户名称: <input type="text" name="name" ><br/>
    账户金额: <input type="text" name="money" ><br/>
    账户省份: <input type="text" name="address.provinceName" ><br/>
    账户城市: <input type="text" name="address.cityName" ><br/>
    <input type="submit" value="保存">
</form>
实体类代码
//账户信息
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
private Address address;
//getters and setters
}

//地址的实体类
public class Address implements Serializable {
private String provinceName;
private String cityName;
//getters and setters
}

控制器代码
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
    System.out.println("保存了账户。。。。 "+account);
    return "success";
}

POJO 类中包含集合类型参数

第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给List 集合中的元素赋值, 使用下标。给 Map 集合中的元素赋值, 使用键值对。

第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现

实体类代码
// 用户实体类
public class User implements Serializable {
    private String username;
    private String password;
    private Integer age;
    private List<Account> accounts;
    private Map<String,Account> accountMap;
    //getters and setters
}

控制器代码
@RequestMapping("/updateAccount")
public String updateAccount(User user) {
    System.out.println("更新了账户。。。。 "+user);
    return "success";
}
jsp 代码:
<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>

自定义类型转换器

当参数通过URL或者表单传递时都会转换为字符串,前面形参为Integer时也不会报错是因为SpringMVC可以实现一些数据类型的自动转换。内置转换器全都在:org.springframework.core.convert.support 包下 ,有java.lang.Boolean -> java.lang.String : ObjectToStringConverter java.lang.Character -> java.lang.Number : CharacterToNumberFactory java.lang.Character -> java.lang.String : ObjectToStringConverter java.lang.Enum -> java.lang.String : EnumToStringConverter

……………………………………等很多。

如遇特殊类型转换要求,需要我们自己编写自定义类型转换器

第一步定义一个类实现 Converter 接口该接口有两个泛型

public interface Converter<S, T> {//S:表示接受的类型, T:表示目标类型
/**
* 实现类型转换的方法
*/
@Nullable
T convert(S source);
}


//自定义类型转换器
public class StringToDateConverter implements Converter<String, Date> {

    //用于把 String 类型转成日期类型
    @Override
    public Date convert(String source) {
        DateFormat format = null;
        try {
            if(StringUtils.isEmpty(source)) {
                throw new NullPointerException("请输入要转换的日期");
            }
            format = new SimpleDateFormat("yyyy-MM-dd");
            Date date = format.parse(source);
            return date;
        } catch (Exception e) {
            throw new RuntimeException("输入日期有误");
        }
	}
}
第二步:在 springMVC 配置文件中配置类型转换器。
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。

<!-- 配置类型转换器工厂 -->
<bean id="converterService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <!-- 要给 converters属性注入值,是个set集合-->
    <property name="converters">
        <set>
        	<!-- 配置自定义类型转换器 -->
        	<bean class="com.mg.converter.StringToDateConverter"></bean>
        </set>
	</property>
</bean>

第三步:在 annotation-driven 标签中引用配置的类型转换服务
<!-- 引用自定义类型转换器 -->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>

响应数据和结果视图

返回值分类

字符串

controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。

@RequestMapping("/testReturnString")
public String testReturnString() {
    System.out.println("AccountController 的 testReturnString 方法执行了。。。。 ");
    //此字符串会通过配置文件中配置的视图解析器解析为物理路径:如 /WEB-INF/pages/success.jsp
    return "success";
}

void

如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。默认会跳转到@RequestMapping(value=”/hello”) hello的页面

也可以使用servlet原生API操作请求转发或者重定向跳转到指定的页面

@RequestMapping(value = "/converter1",method = RequestMethod.POST)
public void converter1(HttpServletRequest request, HttpServletResponse response) {
    //使用 request 转向页面:请求转发
	request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
    
    //也可以通过 response 页面重定向:
    response.sendRedirect("testRetrunString");
    
    //也可以通过 response 指定响应结果, 例如响应 json 数据:
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/json;charset=utf-8");
    response.getWriter().write("json 串");
}

ModelAndView

ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值 。

返回 ModelAndView 类型时,浏览器跳转是请求转发

@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
    ModelAndView mv = new ModelAndView();
    //存值
    mv.addObject("username", "张三");
    //跳转的页面,会通过视图解析器解析为物理视图地址  如:/WEB-INF/pages/success.jsp
    mv.setViewName("success");
    return mv;
}
响应的 jsp 代码:success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>执行成功</title>
    </head>
    <body>
        执行成功!
        ${requestScope.username}
    </body>
</html>

转发和重定向

forward请求转发

controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。 我们也可以写成:

@RequestMapping("/testForward")
public String testForward() {
	System.out.println("AccountController 的 testForward 方法执行了。。。。 ");
    return "forward:/WEB-INF/pages/success.jsp";
}

需要注意的是如果用了 formward 则路径必须写成实际视图 url不能写逻辑视图转发的JSP路径不走视图解析器了所以需要编写完整的路径
它相当于 request.getRequestDispatcher("url").forward(request,response) 使用请求转发既可以转发到 jsp也可以转发到其他的控制器方法

Redirect 重定向

contrller 方法提供了一个 String 类型返回值之后, 它需要在返回值里使用:redirect:

@RequestMapping("/testRedirect")
public String testRedirect() {
    System.out.println("AccountController 的 testRedirect 方法执行了。。。。 ");
    return "redirect:testReturnModelAndView";
    //return "redirect:/add.jsp";重定向到jsp页面
}
它相当于response.sendRedirect(url) 需要注意的是如果是重定向到 jsp 页面 jsp 页面不能写在 WEB-INF 目录中否则无法找到

ResponseBody响应json数据

该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如: json,xml 等,通过 Response 响应给客户端

Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包

jsp 中的代码:
<script type="text/javascript"
    src="${pageContext.request.contextPath}/js/jquery.min.js">
</script>
<script type="text/javascript">
    $(function(){
        $("#testJson").click(function(){
            $.ajax({
                type:"post",
                url:"${pageContext.request.contextPath}/testResponseJson",
                contentType:"application/json;charset=utf-8",
                data:'{"id":1,"name":"test","money":999.0}',
                dataType:"json",
                success:function(data){
                    alert(data);
                }
            });
        });
    })
</script>

<input type="button" value="测试 ajax 请求 json 和响应 json" id="testJson"/>
控制器中的代码:
@Controller("jsonController")
public class JsonController {
    @RequestMapping("/testResponseJson")
    @ResponseBody
    public Account testResponseJson(@RequestBody Account account) {
        System.out.println("异步请求: "+account);
        return account;
    }
}

请求参数乱码问题

post 请求方式:在 web.xml 中配置一个过滤器

<!-- 配置 springMVC 编码过滤器 -->
<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>

get 请求方式:tomacat 对 GET 和 POST 请求处理方式是不同的, GET 请求的编码问题, 要改 tomcat 的server.xml

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>

如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
即可

静态资源访问

  1. 在web.xml中 配置url-pattern标签时,在没有特殊要求的情况下, SpringMVC 的中央调度器 DispatcherServlet 的url-pattern使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等。
  2. 可以写为/,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、 .js、 .jpg、 .png等资源的获取请求,当作是一个普通的 Controller 请求。 中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。

url-pattern的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。

使用mvc:default-servlet-handler标签

只需要在 springmvc.xml 中添加mvc:default-servlet-handler标签即可

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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">

	<mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>

声明了<mvc:default-servlet-handler/>后,springmvc框架会在容器中创建DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet 处理。一般的服务器都有默认的Servlet。
在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。其<servlet-name/>为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。

使用mvc:resources

在 Spring3.0 版本后, Spring 定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了mvc:resources标签,专门用于解决静态资源无 法访问问题。 需要在 springmvc 配置文件中添加如下形式的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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">
    <mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
</beans>

location 表示静态资源所在目录。 当然, 目录不要使用/WEB-INF/及其子目录。
mapping表示对该资源的请求(以/images/开始的请求,如/image/beauty.jpg,/images/car.png等)。注意,后面是两个星号**代表该目录下的文件及子目录下的文件

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦