接上篇:
上篇的末尾提到了contextConfigLocation,DispatchServlet初始化的参数配置,这个是spring启动时加载文件时所配置的参数使用的,比如我们的applicationContext.xml ,[servlet-name]-servlet.xml这些文件如果不是放在spring要求的默认的位置的时候,用contextConfigLocation来指定文件的位置,如:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml</param-value>
</context-param>
这些字符串的参数代表的配置文件,被解析成为spring的上下文的实例,如果这些参数定义多次的话,最新定义的位置则会被使用。
还有另外两个参数:contextClass,namespace,我按照自己的方式把它们从官方文档上翻译过来:
contextClass实现了WebApplicationContext接口,作为核心servlet的一个上下文使用,默认情况下是:xmlWebApplicationContext,
namespace则是指WebApplicationContext的上下文,默认情况下是[servlet-name]-servlet.,这正是代表了[servlet-name]-servlet.xml 的前缀。
注解Controller
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
上面的代码中:@Controller是属于类层级别的注解,spring中所有的组件都可以使用@Component来进行注解,代表属于spring中的一个bean组件,而@Controller你可以认为是spring中@Component的一种特殊形式,你无需实现接口和继承一些基类。
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.easy.web"/>
<mvc:annotation-driven/>
<!-- ... -->
</beans>
这样,所有被注解的类和方法都可以被找到并在spring中将bean进行注册和定义,其中的<mvc:annotation-driven/>必须要加上,因为我们在使用springmvc的时候它初始化了好多事情。
@RequestMapping
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
@RequestMapping(method = RequestMethod.GET)
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
@RequestMapping(value="/{day}", method = RequestMethod.GET)
public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
return appointmentBook.getAppointmentsForDay(day);
}
@RequestMapping(value="/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
@RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
从上边的代码中,我们可以看到,@RequestMapping在好多个地方出现,大类可以分为:类层级和方法级别,首先用@Controller来标识这是一个控制器,然后在类层级给出了一个@RequestMapping("/appointments")代表,所有的对这个控制器内所有方法请求都必须带有"/appoinments"的前缀。
URI-Template
@Controller
public class TreeGridController {
@RequestMapping("/bug")
public void treegrid(Bug bug) {
System.out.println(bug.getDesc());
}
@RequestMapping("/find/{userId}")
public void findUser(@PathVariable String userId) {
System.out.println(userId);
}
}
上面代码中第二个方法就是就是URI模版的方法,这里需要指出@ReqeustMapping中的变量一定要和findUser()中方法参数的名称一样,如果不一样的话,这里如果你用@PathVariable会报错,在前端我们用find/kitty.do进行调用的时候,后边打印出的结果就是:
kitty
经过测试,@PathVariable查可以省略不写的,不过为了能够显示的看出我们是在用URI-模版,最好还是加上,而且一个方法里面可以含有多个变量,如:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
Pet pet = owner.getPet(petId);
model.addAttribute("pet", pet);
return "displayPet";
}
上边的是docs里的,可以看出带有两个变量的URI,事实上道理清楚,不管带几个变量,写法都是一成不变的。
@RequestMapping("/find/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String extension) {
// ...
}
}
这样就将要映射的方法进行完美的注解了,其中symbolicName部分是指有小写字母组成的,"+"号代表字母出现一次或者多次,连接一个“-”,再连接数字,这样就会映射所有这种情况的Controller。
/find/*.do
这样就匹配find下所有的Controller,spring当然也支持${}点位符来解决路径映射的问题,通常用PropertyPlaceholderConfigurer这个类,这个类可以对当前本地的变量及系统环境变量进行提取使用。
定义@ReqeustMapping的处理方法
spring 拦截器
spring中也有类似于struts2中的拦截器,供我们对请求未到达控制指定控制器之前,对request进行必要的处理, 一般spring mvc中的拦截器需要实现一个接口:HandlerInterceptor,实现这个接口有三个方法:preHandle(),postHandle(),afterCompletion(),从单词的表面意义我们就可以已经知道这几个方法执行的时间,其中preHandle()的返回值是一个boolean类型的,false表示不会继承执行请求链,true才会继续。
<beans>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="officeHoursInterceptor"/>
</list>
</property>
</bean>
<bean id="myInterceptor"
class="com.easyui.MyInterCeptor">
</bean>
<beans>
java类:spring给出一个简单实现的HandlerInterceptorAdapter,用它写出我们的实现类:
package com.easyui.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class MyInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String username = request.getParameter("username");
if(username == null || username.equals("")) {
response.sendRedirect("error.jsp");
return false;
}
return super.preHandle(request, response, handler);
}
}
关于@enableWebMvc还不是特别清楚,用它来完全实现java方式来管理bean的方式,和用xml来管理是两种情况回头找例子再补上,这里只给出用于xml的时候配置的拦截器,在xml中的配置应该是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.easyui.web" />
<mvc:annotation-driven />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/find/*"/>
<bean class="com.easyui.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
xml 配置文件中说明,我们对系统只配置了一个拦截器,就是自己实现的那一个,而且我们拦截Controller的格式是:/find/*,对于其它格式的我们并没有进行拦截。