spring日记(十一):Spring MVC

注解驱动以及REST风格的Spring MVC是spring3.0最出彩的功能之一。

先来定义spring MVC的主控Servlet:DispatcherServlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    //http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!-- ① 配置业务层和持久层的spring配置文件,这些配置文件是业务层父spring容器所使用到的-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/conf/applicationContext.xml</param-value>
    </context-param>
    <!-- ② 负责启动spring容器的监听器,它将引用①处的上下文参数获得spring文职文件地址-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
    <!-- ③ 声明DispatchServlet,这个是spring MVC的主控Servlet
        默认会加载/WEB-INF/baobaotao-servlet.xml(即<servlet-name>-servlet.xml)的
        spring配置文件,启动Web层的spring容器-->
    <servlet>
        <servlet-name>baobaotao</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- ④ 声明被上面定义的servlet所匹配截获的URL模式-->
    <servlet-mapping>
        <servlet-name>baobaotao</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
 
</web-app>

我们知道多个spring容器之间可设置为父子容器关系,实现良好的解耦。在这里,web 层的spring容器将作为业务层spring容器的子容器,即web层容器可以引用业务层容器的bean,而业务层容器却访问不到web层容器的bean。

需要提醒的是,一个web.xml可以配置多个DispatcherServlet,通过其<servlet-mappping>的配置,让每个DispatcherServlet处理不同的请求。

DispatcherServlet遵循约定大于配置原则,多数情况下只要按契约来就行,不过也可以手动修改:

* namespace:默认为<servlet-name>-servlet,修改成springzoo后对应的web层的spring配置文件为/WEB-INF/springzoo.xml

* contextConfigLocation:如果DispatcherServlet上下文对应的spring配置文件有多个,则可以使用这个属性来指定多个配置文件,如classpath:springzoo01.xml,classpath:springzoo02.xml

* publishContext:默认为true,决定是否将WebApplicationContext发布到ServletContext中去。

* publishEvents:boolean类型,当DispatcherServlet处理完一个请求后,是否向容器发布一个ServletRequestHandledEvent事件,默认为true

>> 编写处理请求的控制器:

@Controller
@RequestMapping("/user")
public class UserController {
 
    @Autowired
    private UserService userService;
 
    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView createUser(User user) {
        userService.createUser(user);
        ModelAndView mav = new ModelAndView();
        mav.setViewName("user/createSuccess");
        mav.addObject("user", user);
        return mav;
    }
 
    @RequestMapping(value = "/register", method = RequestMethod.GET, params = "!myParam")
    public String register(@ModelAttribute("user") User user) {
        return "user/register";
    }
}

在类上面定义的@RequestMapping是相对于部署根目录而言,在方法上定义的相对于类而言,如果类上没有,方法上就是相对于根目录而言,而return返回的字符串是一个逻辑视图名,怎样去映射到一个真正的视图对象,这个就需要视图解析器了。

配置spring MVC的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        //http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        //http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        //http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
    <!-- 扫描web目录下的类,让所有的spring注解生效-->
    <context:component-scan base-package="com.baobaotao.web" />
 
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:order="100" p:viewClass="org.springframework.web.servlet.view.JstlView"
        p:prefix="/WEB-INF/views/" p:suffix=".jsp" />
 
    <mvc:annotation-driven conversion-service="conversionService" />

>> 使用@RequestMapping映射请求

在一个普通的POJO类上标注@Controller,再通过<context:component-scan/>扫描相应的类包,既可以使POJO称为一个能处理HTTP请求的控制器。

在控制器的类和方法上都能定义@RequestMapping,在类定义初步映射信息,方法处进一步提供详细映射信息,映射规则有URL、请求参数、请求方法、请求头这4个方面的信息,下面分别讲解:

* 通过请求URL进行映射

@RequestMapping(value = "/register")
public String register(@ModelAttribute("user") User user) {
    return "user/register";
}

@RequestMapping不但支持标准URL,还支持Ant风格即? * **的字符,?代表一个字符,*代表任意字符串,**代表任意层级数的目录

@RequestMapping还支持带占位符的URL{XXX},比如/user/**/{userId}

带占位符的URL是spring3新增的功能,该功能在spring MVC向REST目标挺进的发展过程中有里程碑的意义,通过@PathVariable可以将URL中的占位符参数绑定到控制器处理方法的入参中去:

@RequestMapping(value = "/handle44/{imageId}")
public ResponseEntity<byte[]> handle44(@PathVariable("imageId") String imageId) throws Throwable {
    Resource res = new ClassPathResource("/image.jpg");
    byte[] fileData = FileCopyUtils.copyToByteArray(res.getInputStream());
ResponseEntity<byte[]> responseEntity = new ResponseEntity

通过请求方法和请求参数映射,在方法中使用@RequestParam将方法参数和请求参数绑定,利用@RequestHeader将方法参数和请求头参数绑定:

@RequestMapping(value = "/delete", method = RequestMethod.POST, params = "userId")
public String test1(@RequestParam("userId") String userId) {
    // do sth
    return "user/test1";
}

@RequestMapping的value、method、params以及headers分别表示请求URL、请求方法、请求参数以及报文头的映射条件,params和headers支持简单的表达式:

* "userId":表示请求必须包含名为userId的请求参数
* "!userId":表示请求参数不包含userId的请求参数
* "userId!=yidao":表示请求参数包含userId,但不等于yidao
* {"userId=yidao","password"}:表示啥自己去想下
几种典型的用法:
// ①请求参数按名称匹配的方式绑定到方法入参中,方法返回对应的字符串代表逻辑视图名,
    // 如果没有userName这些按契约规定的请求参数,会抛出异常滴
@RequestMapping(value = "/handle1")
public String handle1(@RequestParam("userName") String userName,
        @RequestParam("password") String password,
        @RequestParam("realName") String realName) {
    return "success";
}
 
// ②将Cooke值及报文头属性绑定到入参中、方法返回ModelAndView
@RequestMapping(value = "/handle2")
public ModelAndView handle2(@CookieValue("JSESSIONID") String sessionId,
        @RequestHeader("Accept-Language") String accpetLanguage) {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("success");
    mav.addObject("user", new User());
    return mav;
}
 
// ③请求参数按名称匹配的方式绑定到user的属性中、方法返回对应的字符串代表逻辑视图名
@RequestMapping(value = "/handle3")
public String handle3(User user) {
    return "success";
}
 
// ④直接将HTTP请求对象传递给处理方法、方法返回对应的字符串代表逻辑视图名
@RequestMapping(value = "/handle4")
public String handle4(HttpServletRequest request) {
    return "success";
}
还可以使用命令/表单对象绑定请求参数值:
命令/表单对象就是简单额POJO,并且支持级联绑定,比如detp.deptId, dept.address.tel等:
@RequestMapping(value = "/handle14")
public String handle14(User user) {
    return "success";
}

还能使用Servlet API对象作为入参:

@RequestMapping(value = "/handle21")
public void handle21(HttpServletRequest request, HttpServletResponse response) {
    String userName = request.getParameter("userName");
    response.addCookie(new Cookie("userName", userName));
}
你妹的,居然还可以使用IO对象作为入参,自动将InputStream/Reader绑定到ServletRequest的InputStream/Reader,将OutputStream/Writer绑定到ServletResponse的OutputStream/Writer上面:
@RequestMapping(value = "/handle31")
public void handle31(OutputStream os) throws IOException {
    Resource res = new ClassPathResource("/image.jpg");
    FileCopyUtils.copy(res.getInputStream(), os);
}
 

 本人博客已搬家,新地址为:http://yidao620c.github.io/

猜你喜欢

转载自yidao620c.iteye.com/blog/1844748