springMVC(替代struts)(就是通过配置servlet,使普通的类通过注释被扫描变成控制器)的基本使用方法 1.加入对应的jar包 commons-logging-1.2.jar spring-aop-4.0.0.RELEASE.jar spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar spring-web-4.0.0.RELEASE.jar spring-webmvc-4.0.0.RELEASE.jar 2.在web.xml中直接alt+/,选择#dispatcherservlet <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- <init-param>也可以不配置,那么将使用默认的路径,为/WEB-INF/<servlet-name>-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <!-- spring配置文件的位置 --> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 代表在web应用初始化时创建servlet --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- 开头的/代表web应用的根目录 该servlet处理的请求 会使用servletPath,即/nihao来匹配 /*和/都是匹配所有请求, > /是缺省匹配,优先级最低,也是默认的匹配项 > /*是路径匹配,优先级高于扩展名匹配仅次于精准匹配,会覆盖掉优先级低的匹配 若使用/*会覆盖默认的缺省匹配,那么在刚开始请求index.jsp页面时就匹配了,但找不到对应的响应所以会报404 --> <url-pattern>/</url-pattern> </servlet-mapping> 3.可以看出springMVC是使用了servlet,这是与struts的区别 4.在spring配置文件中 <context:component-scan base-package="handlers"></context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- prefix的value中开头的/代表web应用根目录。 若写了开头的/ >那么响应的页面会是正常的/springMVC-helloworld/WEB-INF/view/success.jsp 若不写开头的/ >@RequestMapping("/QQ")加在类前了,那么响应的页面是/springMVC-helloworld/QQ/WEB-INF/view/success.jsp >@RequestMapping("/QQ")没有加在类前,那么还是正常的/springMVC-helloworld/WEB-INF/view/success.jsp --> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean> 5.编写控制类handler(就是普通的类,通过注释成为了控制器,类似与Action类) @RequestMapping("/QQ") @Controller public class myHandler { /** * @RequestMapping 中value代表会响应的contextPath * 根据spring中的配置,会到prefix+returnValue+suffix。即WEB-INF/view/success.jsp * * * nihao和/nihao其实是一样的,响应是随机选一个,但在初始化时就确定响应哪一个方法了 * * @RequestMapping("/QQ") 若写在类上面,则请求映射信息变为/QQ/nihao * */ // @RequestMapping(value="/nihao") // public String hello2(){ // System.out.println("To Success2"); // return "success2"; // } @RequestMapping(value="nihao") public String hello(){ System.out.println("To Success"); return "success"; } }
1.@RequestMapping(value="nihao"),其中的value支持ant风格匹配 Ant风格 资源地址支持 源地址支持 3 种 ?匹文件名中一个字 *匹文件名中任意字 **匹多层路径 /user/*/createUser: 匹配/user/aaa/createUser、/user/bbb/createUser URL /user/**/createUser: 匹配/user/createUser、/user/aaa/bbb/createUser URL /user/createUser??: 匹配/user/createUseraa、/user/createUserbb URL 2.@PathVariable注解:用于得到URL中的值信息。 在请求映射中添加占位符,在方法形参前加@PathVariable(value="id")注解就可以得到id @RequestMapping("/**/testVariable/{id}") public String testPathVariable(@PathVariable(value="id") int id){} 3.REST风格:表现层状态转化 REST风格的增删改查,分别对应POST,DELETE,PUT,GET请求 4.如何使用PUT,DELETE请求 1.先在web.xml中配置HiddenHttpMethodFilter拦截器 2.必须是POST请求 3.且携带参数_method,它的值就是发出请求的方式 例: <form action="QQ/order/1" method="post"> <input type="hidden" name="_method" value="put"> <input type="submit" value="更新"> </form> <form action="QQ/order/1" method="post"> <input type="hidden" name="_method" value="delete"> <input type="submit" value="删除"> </form> 5.@RequestParam注解(放在形参之前):获取请求的参数,放入形参中 @RequestParam(value="username",required=true,defaultValue="ji") value="username":请求参数的名字 required=true:是否必须携带该请求参数 defaultValue="ji":(一旦设置了defaultValue,required就失效了)当请求不带有该参数时就将其设置为ji 注意:testRequestParam和testRequestParam?username不一样 前者username为ji,是为不带;后者username为"",是为带了 testRequestParam?username&age : username为""。age为null,所以age不能为int而是Integer 6.@CookieValue,@RequestHeader和@RequestParam使用方法相同 7.Pojo作为参数 可以直接将请求的参数封装到方法的形参对象中,而且在表单上可以写级联属性,不需要配置什么 该形参是自定义的普通的java类(Pojo),其中的属性名和表单上<input>的name属性相同 8.Servlet原生的API作为参数 可以直接在方法的形参中写Servlet原生的类对象在方法中使用 支持写ServletRequest,ServletResponse,HttpSession,Principal,Locale, InputStream,Reader,OutputStream,Writer。 原理如下: if (ServletRequest.class.isAssignableFrom(parameterType) || MultipartRequest.class.isAssignableFrom(parameterType)) { Object nativeRequest = webRequest.getNativeRequest(parameterType); if (nativeRequest == null) { throw new IllegalStateException( "Current request is not of type [" + parameterType.getName() + "]: " + request); } return nativeRequest; } else if (ServletResponse.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; Object nativeResponse = webRequest.getNativeResponse(parameterType); if (nativeResponse == null) { throw new IllegalStateException( "Current response is not of type [" + parameterType.getName() + "]: " + response); } return nativeResponse; } else if (HttpSession.class.isAssignableFrom(parameterType)) { return request.getSession(); } else if (Principal.class.isAssignableFrom(parameterType)) { return request.getUserPrincipal(); } else if (Locale.class.equals(parameterType)) { return RequestContextUtils.getLocale(request); } else if (InputStream.class.isAssignableFrom(parameterType)) { return request.getInputStream(); } else if (Reader.class.isAssignableFrom(parameterType)) { return request.getReader(); } else if (OutputStream.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getOutputStream(); } else if (Writer.class.isAssignableFrom(parameterType)) { this.responseArgumentUsed = true; return response.getWriter(); } 9.ModelAndView的使用(是一种向域对象中添加属性的方式) 实际上,目标方法返回的字符串最终是被封装成了一个ModelAndView对象。也可以直接返回一个ModelAndView对象。 原来返回的字符串被封装在modelAndView作为view的部分存在;addObject添加的对象作为model部分存在。 model部分在页面上作为request的属性存在。 @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ String viewName = "success"; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("time", new Date());//此处添加的对象在requestScope的域中 return modelAndView; } 10.使用Map,ModelMap,Model作为目标方法的形参 则这些形参中添加的对象 在页面上作为request的属性存在。 @RequestMapping("/testMap") public String testMap(Map<String,Object> names,ModelMap time,Model add,HttpServletRequest request){ names.put("names", Arrays.asList("Ji","Yun","Fei")); time.put("time", new Date()); add.addAttribute("add", new Address("HeNan", "JiaoZuo")); request.setAttribute("age", 12); return "success"; }
<!-- href中的开头的/代表站点的根目录。不写则代表当前文件所在目录 所以此强求为http://localhost:8080/springMVC-helloworld/QQ/nihao --> <a href="QQ/nihao">To Success</a>
<!-- 以下这种方式若什么都不输入就提交和 QQ/testRequestParam?username&age GET请求相同 --> <form action="QQ/testRequestParam" method="post"> <input type="hidden" name="_method" value="get"> <input type="text" name="username"> <input type="text" name="age"> <input type="submit" value="TestReuqestParam"> </form>
Web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- <init-param>也可以不配置,那么将使用默认的路径,为/WEB-INF/<servlet-name>-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <!-- spring配置文件的位置 --> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 代表在web应用初始化时创建servlet --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- 开头的/代表web应用的根目录 该servlet处理的请求 会使用servletPath,即/nihao来匹配 /*和/都是匹配所有请求, > /是缺省匹配,优先级最低,也是默认的匹配项 > /*是路径匹配,优先级高于扩展名匹配仅次于精准匹配,会覆盖掉优先级低的匹配 若使用/*会覆盖默认的缺省匹配,那么在刚开始请求index.jsp页面时就匹配了,但找不到对应的响应所以会报404 --> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>MethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>MethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
spring配置文件
<?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:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="handlers"></context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- prefix的value中开头的/代表web应用根目录。 若写了开头的/ >那么响应的页面会是正常的/springMVC-helloworld/WEB-INF/view/success.jsp 若不写开头的/ >@RequestMapping("/QQ")加在类前了,那么响应的页面是/springMVC-helloworld/QQ/WEB-INF/view/success.jsp >@RequestMapping("/QQ")没有加在类前,那么还是正常的/springMVC-helloworld/WEB-INF/view/success.jsp --> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
控制器MyHandler.java
package handlers; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @RequestMapping("/QQ") @Controller public class MyHandler { /** * @RequestMapping 中value代表会响应的contextPath * 根据spring中的配置,会到prefix+returnValue+suffix。即WEB-INF/view/success.jsp * * * nihao和/nihao其实是一样的,响应是随机选一个,但在初始化时就确定响应哪一个方法了 * * @RequestMapping("/QQ") 若写在类上面,则请求映射信息变为/QQ/nihao * */ // @RequestMapping(value="/nihao") // public String hello2(){ // System.out.println("To Success2"); // return "success2"; // } @RequestMapping(value="nihao") public String hello(){ System.out.println("To Success"); return "success"; } /** * 此外RequestMapping注释还可以使请求更加精准,例如 * * method=RequestMethod.POST,只映射post方式的testRequestMapping请求 * * params={"username=ji","age!=10","!password"}:只映射参数符合条件的请求. * 有username且=ji,有age且!=10",没有password * * headers={""},对请求的头的要求,书写方式和params方式类似 * */ @RequestMapping(value="/testRequestMapping",method=RequestMethod.POST, params={"username=ji","age!=10","!password"}) public String testRequestMapping(){ System.out.println("To Success"); return "success"; } @RequestMapping("/**/testVariable/{id}") public String testPathVariable(@PathVariable(value="id") int id){ System.out.println("PathVariable"+id); return "success"; } @RequestMapping(value="/**/order/{id}",method=RequestMethod.GET) public String testMethodFilterGET(@PathVariable(value="id") int id){ System.out.println("GET"+id); return "success"; } @RequestMapping(value="/**/order",method=RequestMethod.POST) public String testMethodFilterPOST(){ System.out.println("POST"); return "success"; } @RequestMapping(value="/**/order/{id}",method=RequestMethod.PUT) public String testMethodFilterPUT(@PathVariable(value="id") int id){ System.out.println("PUT"+id); return "success"; } @RequestMapping(value="/**/order/{id}",method=RequestMethod.DELETE) public String testMethodFilterDELETE(@PathVariable(value="id") int id){ System.out.println("DELETE"+id); return "success"; } @RequestMapping(value="/testRequestParam",method=RequestMethod.GET) public String testRequestParam(@RequestParam(value="username",required=true,defaultValue="ji") String username, @RequestParam(value="age",required=false,defaultValue="0") Integer age){ System.out.println(username+":"+age); return "success"; } }
控制器2MyHandler.java
package handlers; import java.util.Arrays; import java.util.Date; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import model.Address; import model.User; @Controller public class MyHandler2 { @RequestMapping("/testMap") public String testMap(Map<String,Object> names,ModelMap time,Model add,HttpServletRequest request){ names.put("names", Arrays.asList("Ji","Yun","Fei")); time.put("time", new Date()); add.addAttribute("add", new Address("HeNan", "JiaoZuo")); request.setAttribute("age", 12); return "success"; } @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ String viewName = "success"; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("time", new Date());//此处添加的对象在requestScope的域中 return modelAndView; } @RequestMapping("testCookieValue") public String testCookieValue(@CookieValue("JSESSIONID")String jsessionid){ System.out.println(jsessionid); return "success"; } /** * 可以直接将请求的参数封装到方法的形参对象中,而且在表单上可以写级联属性,不需要配置什么 * 该形参是自定义的普通的java类(Pojo),其中的属性名和表单上<input>的name属性相同 * */ @RequestMapping("testPojo") public String testPojo(User user,HttpServletRequest req){ System.out.println(user); System.out.println(req); return "success"; } }