spring mvc 知识
1. web.xml 配置<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 如果不配置配置文件的位置以及文件名,则会默认的在 WEB-INF/下寻找 <servlet-name>-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring-servlet.xml</param-value>
<!--
如果含有多个配置文件,可同时配置,中间用分隔符隔开即可
<param-value>/WEB-INF/classes/spring-servlet.xml,/WEB-INF/classes/spring-servlet2.xml</param-value>
甚至可以利用通配符来完成
<param-value>/WEB-INF/classes/*.xml</param-value>
这样,即加载 /WEB-INF/classes/目录下的所有 xml文件
-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2.spring-servlet.xml 配置
<context:component-scan base-package="org.yao.controller"></context:component-scan>
<!-- inteceptor 的配置 -->
<mvc:interceptors>
<!--这样 MyInteceptor 就可拦截 以 /background/*的请求了 -->
<mvc:interceptor>
<mvc:mapping path="/background/*" />
<bean class="org.yao.controller.MyInteceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- 国际化的配置 -->
<!-- 注意:id 必须为messageResource,同时需配置 basename属性,value为属性配置文件的名称 -->
<bean id="messageResource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="message"></property>
<!-- 如果是多个 国际化配置文件,则可利用 basenames进行配置 -->
<!-- <property name="basenames">
<list>
<value>message1</value>
<value>message2</value>
</list>
</property> -->
</bean>
<!-- <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> -->
<!-- InternalResourceViewResolver 与 UrlBasedViewResolver 的主要区别是 , InternalResourceViewResolver对UrlBasedViewResolver
进行了封装,对jsp以及jstl技术进行了较好的支持 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 因为InternalResourceViewResolver 默认含有了viewClass,其值就是:org.springframework.web.servlet.view.JstlView -->
<!-- 所以,下面这行,可以去除 -->
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
3. Interceptor
public class MyInteceptor implements HandlerInterceptor {
// 在页面生成后调用,主要用于释放资源
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}
// 在controller处理请求之后,页面生成之前,进行调用
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler, ModelAndView arg3) throws Exception {
}
// 在controller处理请求之前,进行调用
// handler 即为下一个处理对象的引用,如果下一个是 Inteceptor,则handler为 Inteceptor,如果是 controller,则 hanlder为 controller的引用
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler) throws Exception {
return false;
}
}
4. Controller with REST
/*
原始风格
http://localhost:8080/example05_annotation/start.do?name=zhangsan
http://localhost:8080/example05_annotation/start.do?name=lisi
Rest风格:
http://localhost:8080/example05_annotation/start/zhangsan.do
http://localhost:8080/example05_annotation/start/lisi.do
*/
@Controller
public class StartContorllerForRest {
/*
"/start/{name}" 为 url 模板,{} 内的值是可变的
同时,@PathVariable("name") String name 中的@PathVariable("name") name名称必须与 url模板中定义的变量相同
*/
//http://localhost:8080/example05_annotation/start/zhangsan.do
@RequestMapping("/start/{name}")
public String start(@PathVariable("name") String name){
System.out.println("name"+name);
return "start";
}
//http://localhost:8080/example05_annotation/start/zhangsan/20.do
@RequestMapping("/start/{name}/{age}")
public String startForMultiParam(@PathVariable("name") String name,@PathVariable("age") int age){
System.out.println("name="+name+" age="+age);
return "start";
}
@InitBinder
public void initBinder(
WebRequestDataBinder binder) throws Exception {
// if true, 说明值可以为空,否则的话不能为空
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM--dd"), true));
super.initBinder(request, binder);
}
}
5.Controler with redirct
@Controller
public class StartContorllerForRedirect {
// 为了实现 redirect效果,而不是dispatcher,可在返回的逻辑视图前面加入 "redirect:"
@RequestMapping("/start")
public String start(){
return "redirect:start";
}
} Spring MVC --------------------编程问答-------------------- 6. Controler for param
@Controller
public class StartContorllerForParam {
/*
* 强大之处:参数的个数无限制,参数的顺序亦无限制
*/
@RequestMapping("/start1")
public String start1(){
return "start";
}
/*
* 获取session的前提是当前session可用
*/
@RequestMapping("/start2")
public String start2(HttpServletRequest request,HttpServletResponse response,HttpSession session){
return "start";
}
// @PathVariable("name") @RequestParam @CookieValue @RequestHeader 中的 String可以是任意类型,只是如果是Date等其他类型,需绑定属性编辑器
// 即通过 initBinder来实现
//http://localhost:8080/example05_annotation/start/zhangsan.do
@RequestMapping("/start/{name}")
public String start3(@PathVariable("name") String name,@RequestParam String password,@CookieValue String cookieValue,@RequestHeader String header){
return "start";
}
@RequestMapping("/start4")
public String start4(PrintWriter out){
out.write("user name is incorrect");
return "start";
}
// 通过这种方式,在jsp页面上依旧可以访问到这个model
@RequestMapping("/start5")
public String start5(Map<String,String[]> model){
model.put("dept", new String[]{"product","manage"});
return "start";
}
// 实现 Struts中的ModelDriver功能,也是spring的AbstractCommandController效果
// http://localhost:8080/example05_annotation/start6.do?name=zhangsan&password=123
@RequestMapping("/start6")
public String start6(Emp emp){
System.out.println(emp);
return "start";
}
/*
如果需要对绑定异常进行处理,可加入 BindingResult
public String start6(Emp emp,BindingResult result){
System.out.println(emp);
return "start";
}
*/
}
7. Controller for result
@Controller
@RequestMapping("/background")
public class StartContorllerForResult {
/*
* 不返回任何值需注意:
* 如果不调用 printWriter out来输出页面,则 会进行默认调整,跳转的视图是根据请求路径来处理:
* 如:
@RequestMapping("/start")
public void start(){
}
则spirng处理器会根据请求路径 {appName}/background/start.do 默认生成的viewName="background/start"
即 寻找 WEB-INF/view/background/start.jsp
*/
@RequestMapping("/start")
public void start(PrintWriter out){
out.write("name is incorrect");
}
@RequestMapping("/start1")
public String start1(){
return "start";
}
//这种效果实际上是把 返回的emp放到了Model中,由jsp进行读取
// model中的 key为类名,本例为 emp,第一个字符会转换成 小写
@RequestMapping("/start2")
public Emp start2(){
Emp emp=new Emp();
emp.setEmpNo(1);
return emp;
}
//这种效果实际上是把 返回的List<Emp>放到了Model中,由jsp进行读取
// model中的 key为泛型类名+List,本例为 empList,第一个字符会转换成 小写
//Set的效果亦是这样,如 empSet
@RequestMapping("/start3")
public List<Emp> start3(){
return null;
}
// 此Map则将直接作为 model
@SuppressWarnings("rawtypes")
@RequestMapping("/start4")
public Map start4(){
return null;
}
@RequestMapping("/start5")
public ModelAndView start5(){
return null;
}
}
8 Handler Mapping 01
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="controller01.do">Controller01</prop>
<prop key="controller02.do">Controller02</prop>
<prop key="controller03.do">Controller03</prop>
<prop key="controller04.do">Controller04</prop>
<prop key="to_add.do">Controller05</prop>
<prop key="add_emp.do">Controller05</prop>
</props>
</property>
</bean>
<!-- 第一种 controller,即实现 Controller类,或者AbstractController接口 -->
<bean id="Controller01" class="org.yao.controller.Controller01"></bean>
<!-- 第二种Controller,利用spring自有的 ParameterizableViewController来实现,其主要是用于处理直接跳转到view页面的请求,而不需要进行业务处理-->
<bean id="Controller02" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName" value="controller02"></property>
</bean>
<!--
第三种利用spring自有的 UrlFilenameViewController来实现,用途跟 ParameterizableViewController一样,只是省略 valueName的配置,
此类的根据url的前缀来寻找相关的视图,如controller03.do,则相当于 viewName=controller03
-->
<bean id="Controller03" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
<!-- 第四种, -->
<bean id="Controller04" class="org.yao.controller.Controller04">
<property name="commandClass" value="org.yao.model.Emp">
</property>
</bean>
<!-- 第五种, -->
<bean id="Controller05" class="org.yao.controller.Controller05">
<property name="methodNameResolver">
<bean class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver"></bean>
<!-- <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"></bean>-->
<!-- <bean class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName" value="function"></property>
</bean>
-->
</property>
</bean>
public class Controller01 implements Controller {
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
System.out.println("Controller01 is working");
// 返回一个逻辑view的字符串,可有viewResult来指定后缀,如jsp,html
//viewResult 主要作用是视图解析
return new ModelAndView("controller01");
}
}
/*
* 能够封装请求参数到model的controller
* 当然,也可利用SimpleFormController来实现这种请求,
* AbstractCommandController 与 SimpleFormController区别:
*
*/
@SuppressWarnings("deprecation")
public class Controller04 extends AbstractCommandController {
@Override
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command, BindException exception)
throws Exception {
Emp emp=(Emp)command;
System.out.println(emp);
return new ModelAndView("success");
}
// 在没有实现这个方法的时候: 输出 empNo1 namess passwordss hireDatenull
//说明 hireDate属性并没有注入值,为此,需要自己来实现string to date的绑定
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
super.initBinder(request, binder);
}
}
/*
* 继承AbstractCommandController的方式,与下面这种手动封装数据到model相比,快捷而且方便
*/
class Controller04_compare implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Emp emp=new Emp();
emp.setEmpNo(Integer.parseInt((String)request.getAttribute("empNo")));
emp.setName((String)request.getAttribute("name"));
emp.setPassword((String)request.getAttribute("password"));
emp.setHireDate(new SimpleDateFormat("yyyy-MM-dd").parse((String)request.getAttribute("hireDate")));
System.out.println(emp);
return null;
}
}
public class Controller05 extends MultiActionController {
public ModelAndView to_add(HttpServletRequest request,HttpServletResponse response){
HashMap<String,String[]> model=new HashMap<String,String[]>();
model.put("detpList",new String[]{"produce","manage"});
return new ModelAndView("controller03",model);
}
public String add_emp(HttpServletRequest request,HttpServletResponse response,Object command){
/*
* 对于如何绑定,现在还不知道
Emp emp=(Emp)command;
System.out.println(emp);*/
return ("success");
}
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM--dd"), true));
super.initBinder(request, binder);
}
}
9.Handler Mapping 02
<!--
ControllerClassNameHandlerMapping 与 SimpleUrlHandlerMapping的区别:
不用配置 url到具体controller的映射
默认规则是 根据url的请求来完成,如 abc.do则会转发到AbcContoller控制器中去处理
而对于一个控制器处理多请求的,则可利用 MultiActionController,如利用InternalPathMethodNameResolver作为methodNameResolver时,
需要注意 url的写法:即:muliteRequestController/to_add.do 或者 muliteRequestController/add_emp.do
-->
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
</bean>
<!--
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="controller01.do">Controller01</prop>
<prop key="controller02.do">Controller02</prop>
<prop key="controller03.do">Controller03</prop>
<prop key="controller04.do">Controller04</prop>
<prop key="to_add.do">Controller05</prop>
<prop key="add_emp.do">Controller05</prop>
</props>
</property>
</bean>
-->
<!-- 利用 ControllerClassNameHandlerMapping来进行映射,bean的id取值无所谓,或者不取 -->
<bean id="Controller01" class="org.yao.controller.AbcController"></bean>
<bean id="Controller05" class="org.yao.controller.MuliteRequestController">
<property name="methodNameResolver">
<bean class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver"></bean>
</property>
</bean>
10 国际化
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<!-- text属性用于指定,如 国际化资源配置文件中没有 welcome的配置,则采用默认的 text作为显示输出 -->
<spring:message code="welcome" text="欢迎光临"></spring:message>
11 validation JSR-303
@RequestMapping
public String addUser(@Valid User user, BindingResult result){
if(result.hasErrors()){
return "fromView";
}
return "redirect:/user_list";
}
public class User{
@NotEmpty
private String name;
@Size(min=20,max=40)
}
jar hibernate-validator-version.jar
validation-api-version.jar
slf.jar
log4j
--------------------编程问答-------------------- 12 REST
以资源为导向
list/useId/update
list/userId/delete
location = username/show?json
@ResponseBody
@RequestMapping(value="/{username}/show",param="json")
public void show(@PathVariable String username){
}
@pararm 相当于 在方法头部加入 @RequestParam String json
当然,使用这种方式需要导入相关的json包,以及配置 contentNegotiatingViewResolver
13 Session
在Controller中加入 @SessionAttribute(name="loginUser")
如果某个方法想在session中保存值,那么只需要 利用 model.addAttribute("loginUser",user) 即可向session中保存这个对象了
14 handler exception
在controller中加入
@ExceptionHandler(value={UserException,OtherException})
public String handlerException(Exception ex, HttpServletRequest request){
request.setAttribute("ex",ex);
return "error";
}
这样,只要在这个controller中发生了 UserException 或者 OtherException, 就会跳转到 error页面
15 sitemesh 学习
16 redirect 传值
public string redirect(RedirectAttribute re){
re.addFlushAttribute("ss","ss");
retrun "redirect:/user/list";
}
这样,就能够在 list页面中获取 ss,其实现方式也是通过session来session,只是在取完之后及时删除了。
17 文件上传
<input type="file" name="photos"/><br/>
<input type="file" name="photos"/><br/>
单个文件上传 MultipartFile photo
多个文件上传 MultipartFile[] photos
BindingResult一定要放在要验证对象的后面
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(@Valid User user,BindingResult binding,@RequestParam(required=false) MultipartFile[] photos,HttpServletRequest req) throws IOException {
if(binding.hasErrors()) {
return "user/add";
}
for(MultipartFile photo:photos) {
if(photo.isEmpty()) continue;
System.out.println(photo.getContentType()+","+photo.getName()+","+photo.getOriginalFilename());
String realpath = req.getSession().getServletContext().getRealPath("/resources/upload/");
System.out.println(realpath);
FileUtils.copyInputStreamToFile(photo.getInputStream(), new File(realpath+"/"+photo.getOriginalFilename()));
}
users.put(user.getUsername(), user);
return InternalResourceViewResolver.REDIRECT_URL_PREFIX+"/user/users";
}
补充:Java , 非技术区