三层架构 将整个业务应用划分为三层
? 表现层:用来和客户端进行数据交互,一般采用MVC设计模式
? 业务层:处理公司具体业务逻辑
? 持久层:用来操作数据库
MVC模型 Model View Controller模型视图控制器
? Model:数据模型,JavaBean的类,用来封装数据
? View:通过jsp, html等展示数据
? Controller:接收用户请求,整个流程的控制器
Spring MVC spring提供的mvc框架
? 与struts2的区别:前者入口为servlet,后者用filter接收请求;前者基于方法,后者基于类(每次执行都会新建一个对象,效率低);前者使用更方便;前者使用JSTL表达式执行效率高,后者使用OGNL表达式开发效率高
?
新建maven项目(不使用骨架)
完善目录结构
在main目录下新建webapp/WEB-INF/web.xml文件并导入约束和新建jsp.index文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Web Application</display-name>
</web-app>
main
/ | java resources webapp
/ WEB-INF index.jsp
|
web.xml
添加web moudules
打开project structure的Modules添加Web
设置Deployment Descriptors的Path为web.xml文件的路径
设置Web Resource Directories的为webapp目录的路径
配置pom.xml
<properties>
<!-- 版本锁定 -->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
</dependencies>
配置Tomcat
创建springmvc.xml(resources目录下,ioc下的bean.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: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">
</beans>
配置web.xml
<web-app>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定springmvc配置文件路径 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 启动服务器就加载此servlet,默认发请求时才创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
编写View
在WEB-INF下编写index.jsp(用a或form发送请求)和返回页面pages/success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Start Program</title>
</head>
<body>
<a href="hello">Start Program</a>
</body>
</html>
配置springmvc.xml
<bean ...>
<!-- 开启扫描注解 -->
<context:component-scan base-package="com.whteway"/>
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 文件所在路径 -->
<property name="prefix" value="/pages/"/>
<!-- 文件后缀名 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 开启SpringMVC框架注解支持,自动加载处理映射器、处理适配器和注解处理器 -->
<mvc:annotation-driven/>
</bean>
编写控制器类
@Controller //放入IOC容器
public class HelloController{
@RequestMapping("/hello") //处理路径为hello的请求
public String sayHello(){
//TODO
return "success"; //根据视图解析器找到对应success的页面并返回
}
}
@RequestMapping
可以放在类或方法上,放在类上时可以定义路径公共前缀(分模块)
属性path:用于指定请求的URL
属性value(常用):与path一致,单用value的时候可以省略掉value=
属性method(常用):定义能接收的请求方法,method={RequestMethod.POST}
属性params:用于指定限制请求参数的条件
? 如@RequestMapping(value="/hello", params={"username"})则请求的参数必须有username
? 如params={"username=abc"}则传过来的username必须为abc,还可以用!表示不等于
属性headers:用于指定限制请求消息头的条件
? 如headers={"Accept"}则请求中必须包含有Accept请求头
多个属性同时出现,关系为与
绑定机制(名字相同,自动注入)
支持的数据类型
基本数据类型和String:区分大小写
实体类型(JavaBean)
表单数据的name要与JavaBean的属性名相同,方法参数中加一个JavaBean类型的参数,自动封装名称随意
若JavaBean类中包含其他的引用类型,则表单name为对象.属性,如address.name
集合数据类型
解决中文乱码(web.xml中配置)
<!-- 配置解决中文乱码的过滤器 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
自定义类型转换器
编写转换类实现Converter接口
import org.springframework.core.convert.converter.Converter;
public class StringToDateConvert implements Converter<String,Date>{
@Override
public Date convert(String source){
if(source == null){
throw new RuntimeException("请传入数据");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try{
return df.parse(source);
} catch(Exception e){
throw new RuntimeException("数据类型转换出现错误");
}
}
}
配置自定义类型转换器(springmvc.xml中)
<!-- 配置自定义类型转换器 -->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="包路径.StringToDateConverter"/>
</set>
</property>
</bean>
<!--修改注解支持使转换器生效-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
获取servlet原生API
在方法参数中加对应类型的参数,如HttpServletRequest request, HttpServletResponse response
request.getSession()可以拿到HttpSession
Model(最常用)
方法参数接收一个Model model(map结构),向model中存值,值会自动存入request域中,可以代替获取原生request方式,存用set(),取用get(),取值时可以用实现类ModelMap
@RequestParam
用在方法的参数前,把请求中指定名称的参数给控制器中的形参赋值,当页面参数与方法参数名不一致时可以用
属性value:请求参数中的名称
属性required:是否必须提供此参数,默认true
@RequestBody
@PathVariable
@RequestHeader(不常用)
@CookieValue(不常用)
@ModelAttribute
在控制器方法执行前对参数进行预处理
用在参数上,获取指定的数据给参数赋值,当表单提交的数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据
@RequestMapping("/user") //此方法的参数user是findUser方法的返回值
public String test(User user){}
@ModelAttribute
public User findUser(String name){
//数据库中根据传入参数name查找user
return user;
}
@ModelAttribute //无返回值写法,取参时参数上要用@ModelAttribute("u")
public void findUser(String name, Map<String, User> map){
//数据库中根据传入参数name查找user
map.put("u", user);
}
@SessionAttribute
页面跳转及存值
字符串:根据前端控制器配置好的前缀和后缀找到要跳转的页面,存值用model,底层用ModelAndView实现
void
默认跳转以路径名为名的jsp文件
使用request.getRequestDispatcher("/WEB-INF开始路径全名").forward(request,response); return;进行请求转发
使用response.sendRedirect(request.getContextPath+"/index.jsp");进行重定向
直接进行响应
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("hello");
ModelAndView
使用关键字进行转发和重定向(不能使用视图解析器)
响应json数据
springmvc.xml中配置前端控制器不拦截的静态资源
<mvc:resources mapping="/js/**" location="/js/**" />
添加坐标,导入jackson包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
接收json数据,用JavaBean作为参数接收,参数上用@RequestBody,后台自动将json按照名称封装进JavaBean
响应json数据,在返回值类型前加@ResponseBody,后台自动将JavaBean转换为json
@RequestMapping("/test")
public @ResponseBody User test(@RequestBody User user){
//TODO
return user;
}
文件上传
导入坐标
<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>1.3.1</version>
</dependency>
编写前端代码
配置文件解析器(beanId为固定写法,springmvc.xml)
<bean id="multipartResolver" class="org.springframework.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
编写控制器方法(参数中的upload必须对应表单中文件的name)
@RequestMapping("/upload")
public String fileupload(HttpServletRequest request, MultipartFile upload) throws Exception{
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads");
File file = new File(path);
if(!file.exists()){file.mkdirs();}
//说明上传文件项
//获取文件名称
String filename = upload.getOriginalFilename();
//把文件的名称设置唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
//完成文件上传
upload.transferTo(new File(path, filename));
return "success";
}
传统文件上传的控制器方法的写法
@RequestMapping("/traUpload")
public String traFileupload(HttpServletRequest request) throws Exception{
//使用fileupload组件完成文件上传
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
File file = new File(path);
if(!file.exists()){file.mkdirs();}
//解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
//判断对象是否是上传文件项
if(item.isFormField()){
//为普通表单项
}else{
//为上传文件项
//获取文件名称
String filename = item.getName();
//完成文件上传
item.write(new File(path, filename));
//删除临时文件
item.delete();
}
}
跨服务器上传文件
准备另一个文件上传专用项目,按照路径写好文件上传的控制器方法
@RequestMapping("/upload")
public String fileupload(HttpServletRequest request, MultipartFile upload) throws Exception{
//定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
//说明上传文件项
//获取文件名称
String filename = upload.getOriginalFilename();
//把文件的名称设置唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
//完成文件上传
//创建客户端的对象
Client client = Client.create();
//和图片服务器进行连接
WebResource webResource = client.resource(path+filename);
//上传文件
webResource.put(upload.getBytes());
return "success";
}
异常处理
出现异常后跳转到自定义的友好页面,默认情况下各层出现异常后都向上一级抛出,最终会到视图层,可以在前端控制器处配置一个异常处理器,在异常处理器中处理异常
编写自定义异常类(做提示信息)
public class SysException extends Exception{
//存储提示信息的
private String message;
public String getMessage(){
return message;
}
public String setMessage(String message){
this.message = message;
}
public SysException(String message){
this.message = message;
}
}
编写异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(...){
//获取异常对象
SysException e = null;
if(e instanceof SysException)
e = (SysException)e;
else
e = new SysException("系统正在维护...");
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg", e.getMessage());
mv.setViewName("error"); //提前写好error.jsp页面
return nmv;
}
}
配置异常处理器(跳转到提示页面,springmvc.xml)
<bean id="sysExceptionResolver" class="异常处理器全限定类名"/>
在可能出现异常的地方catch到异常后new一个新的自定义异常对象存入提示信息并throw
try{
int a = 10/0;
} catch(Exception e){
e.printStackTrace();
throw new SysException("赋值失败...");
}
拦截器
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理,也是AOP思想的具体应用
拦截器与过滤器的区别
过滤器是servlet规范中的一部分,任何java web项目都能用
拦截器是SpringMVC自己的,只有使用了SpringMVC框架的工程才能用
过滤器在url-pattern中配置了/*后可以对所有要访问的资源 拦截
拦截器只会拦截访问的控制器方法,不能拦截jsp,html,css,image,js等静态资源
创建自定义拦截器类(接口方法有默认实现,可以不重写)
public class MyInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(...){
//TODO before controller, 返回true表示放行,不放行可以request转发
return true;
}
@Override
public boolean postHandle(...){
//TODO after controller
return true;
}
@Override
public void afterCompletion(...){
//TODO after showing page
}
}
配置拦截器(springmvc.xml)
<mvc:interceptors>
<mvc:interceptor>
<!-- 要拦截的方法(二选一) -->
<mvc:mapping path="/user/*"/>
<!-- 不拦截的方法(二选一) -->
<mvc:exclude-mapping path=""/>
<!-- 配置拦截器对象 -->
<bean class="拦截器全限定类名"/>
</mvc:interceptor>
</mvc:interceptors>
原文:https://www.cnblogs.com/whteway/p/12037374.html