springMVC 养吾剑总结
基本配置
1、通过web.xml配置前端控制器:
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2、配置视图解析器:
<bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
3、创建url和方法的映射关系
@Controller
public class HelloController {
@RequestMapping(path = "/hello")
public String sayHello(){
System.out.println("hello word");
return "success";
}
}
RequestMapping(path = “/hello”)该注解还可以写在类上,用于指定多级路径。
参数说明:
1、path和value一样,指定路径。
2、mathod,取值范围为枚举类RequestMethod,post和get。
3、params,参数限制表达式。如:{“username”}要求必须带username参数。{“username=hh”}属性值都必须对应。{“username!hh”}属性值不能等于hh。
4、headers,要求请求必须带有指定请求头。{“Accept”}
5、可以用@get@post两个注解替换。
.前端数据接收
使用方法参数接收前端数据,要求html参数name名必须和方法的参数名完全一致
-
基本类型参数
public String login_post(Integer userid, String password)
-
使用map接收基本类型参数,所有参数都会以字符串形式被map接收。
public String login_post(@RequestParam("map") HashMap map)
-
使用bean接收基本类型参数。bean中只有基本类型字段的话,会自动转换。
public String Update(Role role)
-
使用复合类型的bean接收基本类型参数。selectStr可以被封装,role和user需要写role.name,user.name,才能被封装进来。
如果有list或map,也是同样的道理。
strList[0]=‘test’,strList[1]=‘ff’ ,strMap[‘ke1’]=‘fff’,strMap[‘ke2’]=‘fff’;
roles[0].name=‘普通用户’,roles[1].name=‘管理员’,userMap[‘yang’].name=‘yang’,userMap[‘yang’].age=‘12’
public String Update(RoleDto roleDto) public Class RoleDto{ Role role; User user; ArrayList<String> strList;HashMap<String> strMap; ArrayList<Role> roles;HashMap<User> userMap; String selectStr; }
-
使用复合类型接收json复合类型,只要结构一致,就可以通过@RequestBody直接接收。
{username:java,password:12222,StrList:['23','dd']}
public Class User{ String username; String password; ArrayList<String> strList; } public String Update(User user)
-
checkbox类型的同名参数接收,使用string时,用,组合接收。使用string[]时,自动封装成list。获取原生request,方法中有httpservletrequest,httpservletresponse两个参数即可。
tis:
表单中文乱码问题:
需要配置一个characterEncodingFilter的过滤器。并配置初始化参数encoding=UTF-8
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
自动封装时,会有类型转换的问题,基本数据类型可以自动转换,但要涉及到date,或类似LocalDate等类型时,需要注册自定义转换器(Converter只使用非json,json转换需要注册formatter):
public class LocalDateConverter implements Converter<String, LocalDate>{
@Override
public LocalDate convert(String s) {
return LocalDate.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
}
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.jp.haiyou.attendance.web.converter.LocalDateConverter"/>
<bean class="com.jp.haiyou.attendance.web.converter.LocalDateTimeConverter"/>
<bean class="com.jp.haiyou.attendance.web.converter.LocalTimeConverter"/>
<bean class="com.jp.haiyou.attendance.web.converter.DateConverter"/>
</set>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
【常用注解】
@RequestParam
方法参数注解,修饰单一的形参。如@RequestParam(“name”) String username.代表前端的name映射为username。
@PathVariable
方法参数注解,要求url中带有可变参数。用于接收该可变参数。注意,只能用包装类接收!
requestmapping("/test/{sid}")
public string testpath(PathVariable(“sid”)Integer id)
@RequestHeader
方法参数注解,获得请求的请求头信息。
xx(@RequestHeader(“Accept”)String header)
@RequestBody
方法参数注解,使用string获得请求体参数。
@CookieValue
方法参数注解,获取cookie的信息。
@ModelAttribute
方法、方法参数注解。写在方法上时,方法先于所有控制器方法执行。即被@ModelAttribute注解的方法会在Controller每个方法执行之前都执行,因此对于一个Controller中包含多个URL的时候,要谨慎使用。。
注解有返回值方法时,返回值对象会被默认放到隐含的Model(spring封装的request域对象)中,在Model中的key为返回值首字母小写,value为返回的值。
model.addAttribute(“string”, abc);
model.addAttribute(“int”, number);
model.addAttribute(“student”, student);
如果想要指定返回值注入到model对象的名称,可以使用value属性。@ModelAttribute(value = “num”)
注解无返回值方法时:
@ModelAttribute
public void myModel(@RequestParam(required = false) String abc, Model model) {
model.addAttribute("attributeName", abc);
}
可以显示将对象注入。
注入到model对象而没有显式指定名称的变量,非基本类型可以通过类型匹配得出。
显式指定了名称的变量,只能通过参数注解@ModelAttribute(“mit”)方式取出。
可以显示将对象注入。
注入到model对象而没有显式指定名称的变量,非基本类型可以通过类型匹配得出。
显式指定了名称的变量,只能通过参数注解@ModelAttribute(“mit”)方式取出。
@SessionAttributes({“a”,“b”})
类注解,表示某个方法使用model对象将a,b两个对象存储进request作用域中时,同样存储到session汇总。
存储后,可以通过ModelMap.get()方法取值。可以通过SessionStatus.setComplete方法清除@SessionAttributes设置的值。
@SessionAttribute
参数注解,表明方法要取的session参数。
【传递数据到html或jsp】
1、返回字符串,默认通过视图解析器查找到同名jsp返回前端。通过参数获取model类型的对象,通过model.addAttribute方法传递数据.
2、void方法,默认查找conroller requestmapping url的同名jsp返回前端。
3、返回ModelAndView类型,可以通过new ModelAndView.addObject/setViewName的方式添加变量并设置返回的jsp页面。
4、转发和重定向,返回固定格式的字符串:return “forward:/web-inf/pages/success.jsp”; return “redirect:/index.jsp”
配置静态资源不拦截
<!--配置前端使用的静态资源不拦截-->
<mvc:resources mapping="/css/" location="/css/**"/>
<mvc:resources mapping="/images/" location="/images/**"/>
<mvc:resources mapping="/js/" location="/js/**"/>
<!--另一种不拦截静态资源的方法:-->
<mvc:default-servlet-handler />
<!--如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:-->
<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />
<!--增加对静态资源的处理,当前的设置必须在Spring的Dispatcher的前面-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.css</url-pattern>
<url-pattern>/css/</url-pattern>
</servlet-mapping>
配置拦截器
public class UserLoginIntercept implements HandlerInterceptor {}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="userIntercept" class="com.jp.haiyou.attendance.web.intercept.UserLoginIntercept"/>
</mvc:interceptor>
</mvc:interceptors>
【文件上传】
前端】:
1、form表单的enctype取值必须是 multipart/form-data(默认值是application/x-www-form-urlencoded)enctype:是表单请求正文的类型。
2、提供一个文件input控件
后端工具方法】
原始手动流读取法基本很少用了,基本采用阿帕奇提供的commons-fileupload(依赖commons-io)包。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
req.setCharacterEncoding("utf-8");
String path=req.getSession().getServletContext().getRealPath("/uploads");
File uploadFolder = new File(path);
if(!uploadFolder.exists())uploadFolder.mkdirs();
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
List<FileItem> itemList = upload.parseRequest(req);
for (FileItem fileItem : itemList) {
if(fileItem.isFormField()){
System.out.println(new String(fileItem.getFieldName().getBytes("iso-8859-1"),"utf-8")+" value:"+
new String(fileItem.getString().getBytes("iso-8859-1"),"utf-8"));
}else{
String fileName=fileItem.getName();
fileName= UUID.randomUUID().toString().replace("-","")+"_"+fileName;
fileItem.write(new File(uploadFolder,fileName));
fileItem.delete();
System.out.println(fileName+"上传成功");
}
}
使用fileUpload固定步骤:
创建工厂类:DiskFileItemFactory factory=new DiskFileItemFactory();
创建解析器:ServletFileUpload upload=new ServletFileUpload(factory);
使用解析器解析request对象:List list=upload.parseRequest(request)
一个FileItem对象对应一个表单项。FileItem类有如下方法:
String getFieldName():获取表单项的name的属性值。
String getName():获取文件字段的文件名。如果是普通字段,则返回null
String getString():获取字段的内容。如果是普通字段,则是它的value值;如果是文件字段,则是文件内容。
String getContentType():获取上传的文件类型,例如text/plain、image。如果是普通字段,则返回null。
long getSize():获取字段内容的大小,单位是字节。
boolean isFormField():判断是否是普通表单字段,若是,返回true,否则返回false。
InputStream getInputStream():获得文件内容的输入流。如果是普通字段,则返回value值的输入流。
注意:使用表单提交multipart/form-data后,springmvc将不能自动识别表单数据并在controller方法参数中进行自动封装。所有封装结果都是null。
springMVC方式】:
1、 <!--配置文件解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
2、使用同名的MultipartFile对象接收解析后的对象,名称一定要和前端的name一致。使用该方法,其他非文件参数可以正常接收
@RequestMapping("/fileLoad")
public String fileLoad(HttpServletRequest req,String username, String password, Integer money, String[] from, MultipartFile myFile) throws IOException {
String path=req.getSession().getServletContext().getRealPath("/uploads");
String fileName= UUID.randomUUID().toString().replace("-","")+"_"+myFile.getOriginalFilename();
myFile.transferTo(new File(path,fileName));
return "success";
}
【表单验证】
springmvc使用JSR 303 – Bean Validation 规范
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.1.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.CR2</version>
</dependency>
Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式,可以通过messag参数指定回显文字。
Hibernate Validator 附加的 constraint
Constraint 详细信息
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内
自定义效验规则:
创建校验器并实现Validator接口并重写对应的方法即可,supports方法是用来判定要校验的bean类型,validate方法用来完成校验逻辑。
public class CustomerValidator implements Validator {
/**
* 检验验证对象是不是Customer类,如果是则进行检验
*/
@Override
public boolean supports(Class<?> target) {
return Customer.class.equals(target);
}
/**
* 校验用户名是否已经存在
*/
@Override
public void validate(Object target, Errors errors) {
Customer customer = (Customer) target;
String name = customer.getCusName();
if (name.equals("Administrator")) {
errors.rejectValue("cusName", null, "该账号已被使用!");
}
}
}
在controller中使用验证器:
方法中参数使用@Validated Customer customer ,BindingResult bindingResult。这样就会对该对象进行验证,验证信息会由bindingresult进行接收,检查是否有错即可:
if(bindingResult.hasErrors()){
model.addAttribute("allErrors",allErrors);
return "fail";}
有错将所有错误信息传达給jsp显示:
<c:if test="${allErrors!= null}">
<c:forEach items="${allErrors}" var="item">
${item.defaultMessage}
</c:forEach>
</c:if>
加载自己写的验证器:
@InitBinder
public void bindValidator(DataBinder dataBinder) {
dataBinder.setValidator(new CustomerValidator());
}
maven和xml全配置
<spring.version>5.0.2.RELEASE</spring.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.1.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.CR2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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="htyy"></context:component-scan>
<mvc:annotation-driven></mvc:annotation-driven>
<bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置前端使用的静态资源不拦截-->
<mvc:resources mapping="/css/" location="/css/**"/>
<mvc:resources mapping="/images/" location="/images/**"/>
<mvc:resources mapping="/js/" location="/js/**"/>
<!--配置文件解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
<!--配置自定义拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="userIntercept" class="htyy.Intercept.UserIntercept"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>