Hello word(第一个SpringMVC项目)**
先创建一个web程序
a.导包
spring-aop.jar
spring-bean.jar
spring-context.jar
spring-core.jar
spring-web.jar
spring-webmvc.jar
commons-logging.jar
b.创建springmvc.xml
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
</beans>
c.将servlet服务交给springmvc处理(对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" version="3.1">
<display-name>Student_SpringMVC</display-name>
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
/ : 表示拦截一切请求
报错NoClassDefFoundError:缺少jar
(直接复制后面的东西百度就可以找出是哪一个jar包)
创建测试的JSP
index.jsp
<body>
<<a href="hello.do">first springmvc</a>
</body>
hello.jsp
<body>
hello world !! <br>
</body>
servlet层
SpringMVCHandler.java
package org.lanqiao.handler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SpringMVCHandler {
@RequestMapping("hello.do")
public String welcom(){
return "hello";
}
}
@Controller:注解方式注入,相当于在配置文件写bean
@RequestMapping("hello.do"):拦截指定的请求,并返回一个字符串
springmvc.xml文件配置
默认路径:/SpringMVCProject/WebContent/WEB-INF/springmvc.xml(了解)
指定springmvc配置文件的路径,如果要省略,必须放到 默认路径:
/WEB-INF/servetname的值-servlet.xml
/WEB-INF/springDispatcherServlet-servlet.xml
/WEB-INF/springDispatcherServlet-servlet.xml
/WEB-INF/AAA-servlet.xml
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 扫描 有注解的包 -->
<context:component-scan base-package="org.lanqiao.handler"></context:component-scan>
<!--配置视图解析器(InternalResourceViewResolver) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
视图解析器:返回值添加前缀和后缀
RequestMapping映射
在类前加RequestMapping **
映射是 去匹配@RequestMapping注解,可以和方法名、类名不一致
如果在类前面加RequestMapping,则超链接href路径要先写类的RequestMapping
例:
SpringMVCHandler.java
@Controller
@RequestMapping(value="handler")
public class SpringMVCHandler {
@RequestMapping("hello.do")
public String welcom(){
return "hello";//默认使用了请求转发的跳转方式
}
}
<a href="handler/hello.do">first springmvc</a>
http://localhost:8080/Student_SpringMVC/handler/hello.do
return默认使用的是请求转发方式
重定向需要加:return "redirect:***
例:return "redirect:hello;
请求过滤(REST风格)
get、post、delete、put
普通浏览器只支持get、post方式,不支持delete、put
get、post方式过滤
通过method指定 请求方式(get post delete put)
@RequestMapping(value="welcome",method=RequestMethod.POST)//映射
@RequestMapping(value="welcome",method=RequestMethod.GET)
delete、put方式过滤(通过过滤器实现,了解)
过滤器对于请求的拦截是有条件的,约定:1、必须是隐藏域、2.name=“_method”、3、value=“DELETE/PUT”、4、初始请求方式为POST
a、增加过滤器
浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求,该过滤器为HiddenHttpMethodFilter。
web.xml(增加部分)
<!-- 增加HiddenHttpMethodFilte过滤器:目的是给普通浏览器 增加 put|delete请求方式 -->
<filter>
<filter-name>HiddenHttpMethodFilte</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilte</filter-name>
<!--拦截一切请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
b.前端
<form action="handler/testRest/1234" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删">
</form>
i:必须是post方式
ii:通过隐藏域 的value值 设置实际的请求方式 DELETE|PUT
c.控制器
@RequestMapping(value="testRest/{id}",method=RequestMethod.DELETE)
public String testDelete(@PathVariable("id") Integer id) {
System.out.println("delete:删 " +id);
//Service层实现 真正的增
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
通过 method=RequestMethod.DELETE 匹配具体的请求方式
此外,可以发现 ,当映射名相同时@RequestMapping(value="testRest),可以通过method处理不同的请求。
原理
过滤器中 处理put|delete请求的部分源码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
requestToUse = new HttpMethodRequestWrapper(request, paramValue);
}
}
filterChain.doFilter(requestToUse, response);
}
原始请求:request,改请求默认只支持get post header
但是如果 是"POST" 并且有隐藏域 <input type="hidden" name="_method" value="DELETE"/>
则,过滤器 将原始的请求 request加入新的请求方式DELETE,并将原始请求 转为 requestToUse 请求(request+Delete请求)
最后将requestToUse 放入 请求链中, 后续再事情request时 实际就使用改造后的 requestToUse
参数过滤
@RequestMapping(value="welcome",method=RequestMethod.POST,params= {"name=zs","age!=23","!height"})//映射
public String welcome() {
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
- 请求必须是post请求
- 必须有name参数,默认值是zs
- 参数age不能是23,没有age参数也可以
- 必须没有height参数
请求头约定(了解)
@RequestMapping(value="welcome2",headers= {"Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Encoding=gzip, deflate"})
public String welcome2() {
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
- 浏览器中是冒号,这里用等号
- 头与头之间用逗号隔开
ant风格请求路径
ant风格的请求路径
? 单字符
* 任意个字符(0或多个)
** 任意目录
获取动态参数
方法一
@RequestMapping(value="welcome5/{name}")
public String welcome5(@PathVariable("name") String name ) {
System.out.println(name);
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
- @RequestMapping(value=“welcome5/{name}”)接收前台传过来的参数name
前端:1234就是name的值
<form action="handler/testRest/1234" method="post">
<input type="submit" value="增">
</form>
- @RequestMapping将接收到的参数传入方法中注解@PathVariable(“name”)修饰的参数
方法二
直接获取表单中name属性为uname的value的值
@RequestMapping(value="testParam")
//required=false设置传入参数不是必须的
public String testParam(@RequestParam("uname") String name,@RequestParam(value="uage",required=false,defaultValue="23") Integer age) {
// String name = request.getParameter("uname");
System.out.println(name);
System.out.println(age);
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
- 普通传值:@RequestParam
public String welcome5(@PathVariable("name") String name )
- ant风格传值:@PathVariable(路径传值)
public String testParam(@RequestParam("uname") String name)
使用对象接收参数(重要)
使用对象(实体类Student)接受请求参数
在SpringMVC中使用原生态的Servlet API :HttpServletRequest :直接将 servlet-api中的类、接口等 写在springMVC所映射的方法参数中即可:
@RequestMapping(value="testServletAPI")
public String testServletAPI(HttpServletRequest request,HttpServletResponse response) {
// request.getParameter("uname") ;
System.out.println(request);
return "success" ;
}
例:
JSP:
<form action="handler/testObjectProperties" method="post">
id:<input name="id" type="text" />
name:<input name="name" type="text" />
家庭地址:<input name="address.homeAddress" type="text" />
学校地址:<input name="address.schoolAddress" type="text" />
<input type="submit" value="查">
</form>
student.java
package org.lanqiao.entity;
public class Student {
private int id;
private String name;
private Address address ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
package org.lanqiao.entity;
public class Address {
private String homeAddress ;
private String schoolAddress ;
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public String getSchoolAddress() {
return schoolAddress;
}
public void setSchoolAddress(String schoolAddress) {
this.schoolAddress = schoolAddress;
}
}
ServletAPI(req、resp)
required=false设置传入参数不是必须的
- 设置默认值: defaultValue=“23”
通过注解获取头信息
获取请求头信息 @RequestHeader
public String testRequestHeader(@RequestHeader("Accept-Language") String al ) {
通过@RequestHeader("Accept-Language") String al 获取请求头中的Accept-Language值,并将值保存再al变量中
获取cookie的值
通过mvc获取cookie值(JSESSIONID)
@CookieValue
(前置知识: 服务端在接受客户端第一次请求时,会给该客户端分配一个session (该session包含一个sessionId)),并且服务端会在第一次响应客户端时 ,请该sessionId赋值给JSESSIONID 并传递给客户端的cookie中
@RequestMapping(value="testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String jsessionId) {
System.out.println( jsessionId);
return "success" ;// views/success.jsp,默认使用了 请求转发的 跳转方式
}
处理模型数据
如果跳转时需要带数据:V、M,则可以使用以下方式:
ModelAndView、ModelMap 、Map、Model -数据放在了request作用域
@SessionAttributes、@ModelAttribute
示例:
public String testModel(Model model| Map<String,Object> m) {
m.put(x,".."); 就会将x对象 放入request域中
如何将上述数据放入session中?@SessionAttributes(..)
@ModelAndView (☆☆☆☆)
@RequestMapping(value="testModelAndView")
public ModelAndView testModelAndView() {//ModelAndView:既有数据,又有视图
//ModelAndView:Model -M View-V
ModelAndView mv = new ModelAndView("success");//view: views/success.jsp
Student student = new Student() ;
student.setId(2);
student.setName("zs");
mv.addObject("student", student);//相当于request.setAttribute("student", student);
return mv;
}
ModelAndView mv = new ModelAndView(“success”):设置跳转的地址
mv.addObject(“student”, student);//相当于request.setAttribute(“student”, student);
传递的数据(ModelMap 、Map、Model)
**数据都是放在了request作用域 **
**记:ModelMap **
@RequestMapping(value="testModelMap")
public String testModelMap(ModelMap mm) {//success
Student student = new Student() ;
student.setId(2);
student.setName("zs");
mm.put("student2", student);//request域
return "success"; //view
}
@RequestMapping(value="testMap")
public String testMap(Map<String,Object> m) {
Student student = new Student() ;
student.setId(2);
student.setName("zs");
m.put("student3", student);//request域
return "success";
}
@RequestMapping(value="testModel")
public String testModel(Model model) {
Student student = new Student() ;
student.setId(2);
student.setName("zs");
model.addAttribute("student4",student);//request域
return "success";
}
传递数据时放在session中
在class前添加注解:@SessionAttributes(…)
//接口/类 注解 配置
//@SessionAttributes(value="student4") //如果要在request中存放student4对象,则同时将该对象 放入session域中
//@SessionAttributes(types= {Student.class,Address.class}) //如果要在request中存放Student类型的对象,则同时将该类型对象 放入session域中(数组类型)
@Controller
@RequestMapping(value="handler") //映射
public class SpringMVCHandler {
@SessionAttributes(value=“student4”) //如果要在request中存放student4对象,则同时将该对象 放入session域中
@SessionAttributes(types= {Student.class,Address.class}) //如果要在request中存放Student类型的对象,则同时将该类型对象 放 入session
@ModelAttribute (慎用)
@ModelAttribute 在请求 该类的各个方法前 均被执行的设计是基于一个思想:一个控制器 只做一个功能
- i.经常在 更新时使用
- ii.在不改变原有代码的基础之上,插入一个新方法。
- 在任何一次请求前,都会先执行@ModelAttribute修饰的方法
jsp
<form action="handler/testModelAttribute" method="post">
编号:<input name="id" type="hidden" value="31" />
姓名:<input name="name" type="text" />
<input type="submit" value="修改">
</form>
注:@ModelAttribute先查询出student的值放入前台即将传入的参数中,然后前台传入参数,参数就更新了一遍
通过@ModelAttribute修饰的方法 ,会在每次请求前先执行;
并且该方法的参数map.put()可以将 对象 放入 即将查询的参数中;
必须满足的约定:
map.put(k,v) 其中的k 必须是即将查询的方法参数 的首字母小写
testModelAttribute(Student xxx) ,即student;
如果不一致,需要通过@ModelAttribute声明。如下:
@ModelAttribute//在任何一次请求前,都会先执行@ModelAttribute修饰的方法
public void queryStudentById(Map<String,Object> map) {
//StuentService stuService = new StudentServiceImpl();
//Student student = stuService.queryStudentById(31);
//模拟调用三层查询数据库的操作
Student student = new Student();
student.setId(31);
student.setName("zs");
student.setAge(23);
map.put("stu", student) ;//约定:map的key 就是方法参数 类型的首字母小写
}
//修改:Zs-ls
@RequestMapping(value="testModelAttribute")
public String testModelAttribute(@ModelAttribute("stu")Student student) {
student.setName(student.getName());//将名字修改为ls
System.out.println(student.getId()+","+student.getName()+","+student.getAge());
return "success";
}