Stage3-day07-springmvc详解2
springmvc的配置文件的放置位置问题
- 第一种位置是和src平级的位置---config文件夹(source folder),此时需要在前端控制器配置中添加init-param标签实现加载springmvc配置文件,此时此配置文件最终保存到了classes文件夹中. 项目的部署地址我们可以从下图中找出:
- springmvc配置文件放到了WEB-INF文件夹中,此时文件的名称必须符合格式:前端控制器的<servlet-name>标签所定义的名称加中划线加servlet,例如:abc123-servlet.xml;此时前端控制器中init-param标签配置项就可以删除
重定向操作如何实现传参?
借助session,将request域对象中的键值对转存到session域对象中,如何转存:@SessionAttributes
- 第一种实现方式--可能存在弊端. 加入键值对只需要使用一次,那么在用完之后并没有从session域对象中消失,还一直占用空间,不合适;建议采用第二种方式. 当我们使用转发直接传递参数时会出现这样的错误:
package com.offcn.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; @Controller //将键值对放入session域对象中,value就是要放入的key名,由key找到对应的值 @SessionAttributes(value = {"id"}) public class RedirectController { @RequestMapping("/redirect.action") public String address1(int id,Model model) { System.out.println("first:"+id); //model和ModelAndView相当于request,都是向request作用域中添值 //model先把值存放到request作用域中,然后@sessionAttributes注解 //再把request作用域中的值存放到session中,往下传递 model.addAttribute("id", id);//存放进request作用域中 return "redirect:second.action"; } @RequestMapping("/second.action") public String second(HttpServletRequest request) { //二次请求时从session中获取键值对 HttpSession session = request.getSession(); Object id = session.getAttribute("id"); System.out.println("second:"+id); session.setAttribute("att", id);//往页面传参 return "/main2.jsp"; } }
注解@sessionAttributes的value的值时一个字符串数组,值是多个字符串,每个字符串表示一个key名称
-
此方式仅仅只能传递一次参数,同样也时借助session域对象
package com.offcn.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller public class RedirectSecondController { @RequestMapping("/redirectSecond.action") public String second(int id,RedirectAttributes ra) { System.out.println("first:"+id); //RedirectAttributes同样实现将键值对保存到session域对象中,但是只在session对象中保存一次 //id值二次请求的时候拼接到url上了,想要获取id值可以用EL表达式 ra.addAttribute("id", id); //如果不想二次请求中的url中出现id值可以使用此方法 // ra.addFlashAttribute("id",id); return "redirect:/secondcon.action"; } @RequestMapping("/secondcon.action") public String secondRedirect1(@ModelAttribute("id")int id) { System.out.println("second"+id); return "/main2.jsp"; } }
url的说明
在前端的页面中设置超链接或者js或者css等,都会涉及到url,所以url的设计有三种格式:在资源名称前面有/、无/、../;例如:/abc.action、abc.action、../abc.action
三种格式分别要补齐完整的url路径,
第一种补齐时补到8080/,即端口位置
例如:<a href="/bcd.action">提交</a>
补齐后的绝对路径为: http://localhost:8080/bcd.action -->
第二种补齐时要看当前浏览器中地址栏url的情况,即当前页面的地址信息,有可能当前页面地址信息中会含有名称空间
<a href="abc.action">提交</a>
- 超链接没有/,表示相对路径,前面补齐的是当前浏览器地址里url去掉名称剩下的部分. 假如:当前页面的url是http://localhost:8080/day07-springmvc-url/index.jsp,那么就把index.jsp去掉, 之后剩下的就是http://localhost:8080/day07-springmvc-url/abc.action
- 假如:当前的url是http://localhost:8080/day07-springmvc-url/file/index.jsp,该中名称是带名称空间(file)的,那么把index.jsp去掉剩下http://localhost:8080/day07-springmvc-url/file/abc.action
第三种补齐时要看浏览器地址栏的url,只不过要根据url进行向前找路径情况
<a href="../cde.action">提交</a>
- ../是相对路径, 表示从当前url的资源名称部分向前找两级目录,找到的第二级目录的url,给其补齐. 假如:当前的url是http://localhost:8080/day07-springmvc-url/index.jsp,那么找两级之后8080/位置 http://localhost:8080/cde.action
- 假如:当前的url是http://localhost:8080/day07-springmvc-url/file/index.jsp,那么找两级之后是day07-springmvc-url/位置, 补全后为http://localhost:8080/day07-springmvc-url/cde.action
四. 后台在设置url的时候,一般采用绝对路径,后台的绝对路径是包含项目名的
在后台/表示到项目名的位置的url,例如http://localhost:8080/day07-springmvc-url/
@RequestMapping("/abc.action")此时带有/所以补齐的url中带有项目名, 完整格式是http://localhost:8080/day07-springmvc-url/ abc.action
请求方式的转换
1.在页面发出请求的时候,只见过get和post两种请求方式:
- 超链接、js文件加载<script src=”js/jquery.js”>、css文件加载<link href=”css/main.css”>都是发出get请求;
- 表单通过method属性设置get或者post请求
- 异步操作:type属性设置get或者post请求
2.请求方式:get、post、delete、put、head、trace、options
http协议只实现了get和post,所以页面只有两种请求方式被实现了:get和post;
那么其他的请求方式没有被实现,可以通过一种手段模拟其他请求方式,比如delete、put、head等等
3.如何实现模拟
- 必须是post请求才能模拟转换---原始请求是post
-
固定参数对请求的时候的数据key=value, 即 _method=delete/put/...
-
在后端控制器中@RequestMapping注解中添加对应的方式(属性=值)
-
需要配置一个过滤器---请求转换的过滤器 请求方式和处理方式不匹配时会报405异常处理方式是加一个请求转换过滤器
package com.offcn.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class PutController { //传参方式的模拟,需要在requesmapping中使用requestmethod属性 //当有多个属性的时候,requestmapping中的value不能省略 @RequestMapping(value="/put.action",method = RequestMethod.PUT) public String put(int id) { System.out.println(id); //在转发此main页面时是我们转化后的put请求,但是此时页面的响应使用的是 //Servlet中的doget请求方式,因为jsp本身就是一个简化的servlet,所以请求方式 //和处理请求的方式不匹配--405异常 return "redirect:/show.action"; } @RequestMapping("/show.action")//自适应请求方式,如果指定了method就是指定请求方式 public String show() { return "/WEB-INF/main.jsp"; } }
5.一般情况下可能会根据不同的CRUD操作,来对应不同的请求方式;即如果是查询操作--使用get请求、如果是保存操作--使用post请求、如果是修改操作--使用put请求、如果是删除操作--使用delete请求
数据校验
1.什么是数据校验?--- 是指用来校验数据是否合法---合乎规定
2.数据校验包括页面校验、后台校验;页面校验一般不安全,很容易出现校验被绕行;在对于数据安全要求较高的情况下要采用后台校验
3.在web项目中,规定了一种数据校验模式,称为JSR303校验方式,这种方式参考了Hibernate的数据校验方式,在springmvc中提供了实现JSR303校验的方式,主要在springmvc的框架中整合校验框架
实现步骤
- 需要的jar包---hibernate-validator包,jboss-logging包,validation-api包,classmate包
- 在springmvc的配置文件中添加校验器, 需要先添加工厂bean,在工厂中配置校验器,然后再引入配置文件对象,用来实现软编码
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 扫描包 --> <context:component-scan base-package="com.offcn"></context:component-scan> <!-- 注解方式的适配器和注解方式的映射器 --> <!-- mvc:annotation代替注解的适配器和映射器 --> <mvc:annotation-driven validator="validatorFactory"></mvc:annotation-driven> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean> <!-- 校验器的配置:先工厂,再校验器,这个是工厂 --> <bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- 通过属性添加,这个是校验器 --> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> <!-- 将配置文件加载对象注入到工厂中来 --> <property name="validationMessageSource" ref="messageSource"></property> </bean> <!-- 读取配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <!-- 省略文件的扩展名,属性文件在这里引入 --> <value>classpath:ValidationMessage</value> </list> </property> </bean> </beans>
- 要在实体类的属性上面添加对应的注解, 了解有哪些校验注解?
- 处理请求的执行单元形参位置要添加注解@Validated Person person,BindingResult bindingResult, @Validated注解和BindingResult属性成对出现. 如果我们没有自定义错误输出信息,框架也会有默认的错误信息输出注意message的值是通过{ }引入的,类似于EL表达式,但是没有$符号
-
最后校验结果送回到页面视图
- 创建配置文件比如:ValidationMessage.properites
- 将结果信息抽取到此配置文件中,使用键值对保存,然后再将key引用回到实体类的属性中去引入的时候格式是value="{key}"
校验注解有
非空校验
- @NotNull----此注解通常用于给基本类型对应的包装类做非空校验
- @NotBlank----此注解用于给String类型做非空校验
- @NotEmpty----此注解用于对集合属性做非空校验
闭合区间校验
- @Size---对字符串、集合做区间校验,即最大和最小
- @Length---对字符串做区间校验,最长和最短
- @Range---对字符串、基本类型的包装类做区间校验,即最大值和最小值
其他
- @Email--邮箱格式校验
- @Pattern---自定义正则表达式实现校验
当客户进行数据添加之后,点击提交,在后台实现了数据校验,如果存在校验信息,说明客户所填写内容有不合理的,所以给客户响应页面的时候肯定原界面实体类,各种非空判断在这里进行
package com.offcn.bean;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
public class Person implements Serializable{
private static final long serialVersionUID = -1706595280202149906L;
//id实现非空校验---id必须有值,不能为null
//自定义校验提示---硬编码---软编码(将校验提示信息保存到配置文件)
@NotNull(message = "{person_pid_isnotnull}")
private Integer pid;
@NotBlank(message = "{person_pname_isnotnull}")
@Length(max = 16,min = 6)
private String pname;
private String pdate;
@NotBlank(message = "邮箱不能为空")
@Email(message = "{person_email}")
private String email;
private Double pweight;
//自定义正则表达式实现手机号码校验
@Pattern(regexp = "^1[3-9][0-9]{9}$",message = "手机号码格式不正确")
private String phone;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public String getPdate() {
return pdate;
}
public void setPdate(String pdate) {
this.pdate = pdate;
}
public Double getPweight() {
return pweight;
}
public void setPweight(Double pweight) {
this.pweight = pweight;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
index页面,页面回显数据
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%-- <%
String url = request.getSession().getServletContext();
%> --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 将校验信息展示 -->
<!-- 判断键值对是否存在,存在才展示 -->
<c:if test="${errors != null }">
<c:forEach items="${errors }" var="er">
${er.defaultMessage }<br>
</c:forEach>
</c:if>
<form action="person1.action">
<input type="text" name="pid">
<input type="text" name="pname">
<input type="text" name="email">
<input type="text" name="phone">
<input type="submit" value="提交">
</form>
</body>
</html>
springmvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描包 -->
<context:component-scan base-package="com.offcn"></context:component-scan>
<!-- 注解方式的适配器和注解方式的映射器 -->
<!-- mvc:annotation代替注解的适配器和映射器 -->
<mvc:annotation-driven validator="validatorFactory"></mvc:annotation-driven>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>
<!-- 校验器的配置:先工厂,再校验器,这个是工厂 -->
<bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- 通过属性添加,这个是校验器 -->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<!-- 将属性配置文件加载对象注入到工厂中来 -->
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- 读取配置文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<!-- 省略文件的扩展名,属性文件在这里引入 -->
<value>classpath:ValidationMessage</value>
</list>
</property>
</bean>
</beans>
控制层
package com.offcn.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import com.offcn.bean.Person;
@Controller
public class PersonController {
@RequestMapping("/person1.action")
//@Validated注解和BindingResult属性成对出现
public String person1(Model model,@Validated Person person,BindingResult bindingResult) {
//获取校验结果
List<ObjectError> allErrors = bindingResult.getAllErrors();
for(ObjectError oe : allErrors) {
System.out.println(oe.getDefaultMessage());
}
//需要判断---有校验信息,回原界面;没有校验信息才到正常页面
if(bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "/index.jsp";
}
return "/WEB-INF/main.jsp";
}
}