SpringMVC学习
---------------------基础
SpringMVC是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。
1.三层架构和MVC模型
1.三层架构
咱们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序
使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构
三层架构
表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
业务层:处理公司具体的业务逻辑的
持久层:用来操作数据库的
2.MVC模型
MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
Model:数据模型,JavaBean的类,用来进行数据封装。
View:指JSP、HTML用来展示数据给用户
Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
2.SpringMVC的入门
1.创建WEB工程,引入开发的jar包
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>//版本锁定
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<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>
2.配置核心的控制器(配置DispatcherServlet)
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
<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>
3.编写springMVC配置文件
<!--配置spring要扫描的包-->
<context:component-scan base-package="com.itheima"/>
<!--配置视图解析器 解析springMapping返回的路径-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--处理器映射器,处理适配器,视图解析器称为springMVC三大组件-->
<!-- 配置spring开启注解mvc的支持-->
<!--配置这个就自动加载处理器映射器,处理适配器-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
4.编写index.jsp和HelloController控制器类
<a href="hello">入门程序</a>
@Controller
public class HelloController {
/*入门案例*/
@RequestMapping(path = "/hello")
public String hello(){
System.out.println("hello方法执行了");
return "success";
}
5.在WEB-INF下建pages/success.jsp的成功页面
<h3>入门成功</h3>
3.环境搭建
1.入门案例的流程
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
- 开启了注解扫描,那么HelloController对象就会被创建
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
详细分析
2.的组件分析
- 前端控制器(DispatcherServlet)
- 处理器映射器(HandlerMapping)
- 处理器(Handler)
- 处理器适配器(HandlAdapter)
- 视图解析器(View Resolver)
- 视图(View)
4. RequestMapping注解
-
RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
-
RequestMapping注解可以作用在方法和类上
作用在类上:第一级的访问目录
作用在方法上:第二级的访问目录
细节:路径可以不编写 / 表示应用的根目录开始
细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
-
RequestMapping的属性
path 指定请求路径的url
value value属性和path属性是一样的
mthod 指定该方法的请求方式
params 指定限制请求参数的条件
headers 发送的请求中必须包含的请求头
5. 请求参数的绑定
1.请求参数的绑定说明
1.绑定机制
表单提交的数据都是k=v格式的 username=haha&password=123
SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
要求:提交表单的name和参数的名称是相同的
2.支持的数据类型
基本数据类型和字符串类型
实体类型(JavaBean)
集合数据类型(List、map集合等)
2.基本数据类型和字符串类型
提交表单的name和参数的名称是相同的
区分大小写
3.实体类型(JavaBean)
提交表单的name和JavaBean中的属性名称需要一致
如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例
address.name
4.给集合属性数据封装
JSP页面编写方式:list[0].属性
6. 自定义类型转换器
1.表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。
2.如果想自定义数据类型转换,可以实现Converter的接口
public class StringToDateConverter 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("数据类型转换出现错误");
}
}
}
3.注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!--处理器映射器,处理适配器,视图解析器称为springMVC三大组件-->
<!-- 配置spring开启注解mvc的支持-->
<!--配置这个就自动加载处理器映射器,处理适配器-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
7.常用的注解
RequestParam注解
作用:把请求中的指定名称的参数传递给控制器(Controller)中的形参赋值
-
value:请求参数中的名称
-
required:请求参数中是否必须提供此参数,默认值是true,必须提供
@RequestMapping(path="/hello") public String sayHello(@RequestParam(value="username",required=false)String name) { System.out.println("aaaa"); System.out.println(name); return "success"; }
RequestBody注解
-
作用:用于获取请求体的内容(注意:get方法不可以)
-
属性 1. required:是否必须有请求体,默认值是true
@RequestMapping(path="/hello") public String sayHello(@RequestBody String body) { System.out.println("aaaa"); System.out.println(body); return "success"; }
PathVariable注解
-
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
-
属性 value:指定url中的占位符名称
-
Restful风格的URL
1.请求路径一样,可以根据不同的请求方式去执行后台的不同方法
2.restful风格的URL优点
结构清晰
符合标准
易于理解
扩展方便
@RequestMapping(path="/hello/{id}")
public String sayHello(@PathVariable(value="id") String id) {
System.out.println(id);
return "success";
}
RequestHeader注解
-
作用:获取指定请求头的值
-
属性 value:请求头的名称
@RequestMapping(path="/hello") public String sayHello(@RequestHeader(value="Accept") String header) { System.out.println(header); return "success"; }
CookieValue注解
-
作用:用于获取指定cookie的名称的值
-
属性 value:cookie的名称
@RequestMapping(path="/hello") public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) { System.out.println(cookieValue); return "success"; }
ModelAttribute注解
1.作用
1.出现在方法上:表示当前方法会在控制器方法执行前线执行。
2.出现在参数上:获取指定的数据给参数赋值。
2.应用场景
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
3.具体的代码
//@ModelAttribute:1.在执行操作之前执行,有返回值,且把那个user返回到当前user了
//2.在执行操作之前执行,无返回值,在当前方法属性配置如下也能获取
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(@ModelAttribute("aaa") User user){
System.out.println("执行了...");
System.out.println(user);
return "success";
}
@ModelAttribute
public void getUser(Map<String,User> map){
User user = new User();
user.setUname("haha");
user.setAge(13);
user.setDate(new Date());
map.put("aaa",user);
}
// @ModelAttribute
// public User getUser(){
// User user = new User();
// user.setUname("haha");
// user.setAge(13);
// user.setDate(new Date());
// return user;
// }
SessionAttributes注解
-
作用:用于多次执行控制器方法间的参数共享 (将指定属性存入session域中)
-
属性 value:指定存入属性的名称
@Controller
@RequestMapping("/anno")
@SessionAttributes(value={"lqd"}) // 把msg=美美存入到session域对中
//先在类上写@SessionAttributes注解并根据存入request中的内容再转存入session域中才能取
public class AnnoController {
@RequestMapping(value="/saveSessionAttributes")
public String saveSessionAttributes(Model model){
// 底层会存储到request域对象中
model.addAttribute("lqd","刘乾东");
model.addAttribute("mmd","美美的");
return "success";
}
@RequestMapping(value="/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
//根据名称获取session域的对象的值
String naem = (String)modelMap.get("lqd");
System.out.println(naem);
return "success";
}
@RequestMapping(value="/deleteSessionAttributes")
public String deleteSessionAttributes(SessionStatus sessionStatus){
//清除session域
sessionStatus.setComplete();
return "success";
}
}
--------------------使用
1.数据响应和结果视图
1.请求转发.重定向
//无返回值请求页面
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("执行了");
//请求转发
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
// return ;
//重定向
// response.sendRedirect(request.getContextPath()+"/index.jsp");
// return ;
//直接在浏览器响应
//设置解决中文乱码
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("你好");
return;
}
2.ModelAndView.跳转
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了...");
// 模拟从数据库中查询出User对象
User user = new User();
user.setUsername("小凤");
user.setPassword("456");
user.setAge(30);
// 把user对象存储到mv对象中,底层也是user对象存入到request对象
mv.addObject("user",user);
// 跳转到哪个页面
mv.setViewName("success");
return mv;
}
3.关键字方式转发或者重定向
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect法执行了...");
//请求转发
return "forward:/WEB-INF/pages/success.jsp";
//重定向
// return "redirect:/index.jsp";
}
4.模拟异步请求响应
注:如果web.xml配置了请求全部拦截,需在springmvc.xml文件配置忽略静态资源拦截
jsp代码
<script src="js/jquery-1.9.1.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
// alert("hello btn");
// 发送ajax请求
$.ajax({
// 编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"hehe","password":"123","age":30}',
dataType:"json",
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}});}); });
</script>
</head>
<body>
<button id="btn">发送ajax请求</button> <br>
java代码
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了...");
// 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
// 做响应,模拟查询数据库
user.setUsername("haha");
user.setAge(40);
// 做响应
return user;
}
2.文件上传
<body>
<%--原本的方式--%>
<form action="user/upload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>//文件上传框
上传文件:<input type="submit" value="点击上传"/><br>
</form><br>
<%--springMVC的方式上传文件--%>
<form action="user/upload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
上传文件:<input type="submit" value="点击上传"/><br>
</form><br>
<%--跨服务器上传文件--%>
<form action="user/upload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
上传文件:<input type="submit" value="点击上传"/><br>
</form><br>
</body>
1.原始方式
@RequestMapping("/upload1")
public String upload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传成功了");
String path = request.getSession().getServletContext().getRealPath("/uploads");
File file = new File(path);
if (!file.exists()){
file.mkdir();
}
//解析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();
//把文件的名称设置唯一值
String uuid = UUID.randomUUID().toString();
filename = uuid+"-"+filename;
//完成文件上传
item.write(new File(path,filename));
//清除缓存
item.delete();
}
}
return "success";
2.springMVC方式
注:需配置springMVC的文件解析器
<!--配置文件解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件大小限制-->
<property name="maxUploadSize" value="11111111"/>
</bean>
@RequestMapping("/upload2")
public String upload1(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("文件上传成功了");
String path = request.getSession().getServletContext().getRealPath("/uploads");
File file = new File(path);
if (!file.exists()){
file.mkdir();
}
//说明上传文件项
//获取上传文件的名称
String filename = upload.getOriginalFilename();
//把文件的名称设置唯一值
String uuid = UUID.randomUUID().toString();
filename = uuid+"-"+filename;
//完成文件上传
upload.transferTo(new File(path,filename));
return "success";
3.跨服务器文件上传
注:跨服务器文件上传需在tomcat安装目录的web.xml文件添加如下代码(因为默认是读访问)
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
@RequestMapping("/upload3")
public String upload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
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";
}
3.异常界面处理
1.编写异常处理器类 需实现HandlerExceptionResolver
public class SysExceptionResolver implements HandlerExceptionResolver{
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 获取到异常对象
SysException e = null;
if(ex instanceof SysException){
e = (SysException)ex;
}else{
e = new SysException("系统正在维护....");
}
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
2.配置文件配置异常处理器
<!--配置异常处理器--><bean id="sysExceptionResolver" class="com.itheima.exception.SysExceptionResolver"/>
3.当捕获到异常会进入异常处理器中
4.可以在异常处理类中处理异常
4.springMVC拦截器
1.概念
-
SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
-
可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
-
拦截器和过滤器的功能比较类似,有区别
过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
拦截器是SpringMVC框架独有的。
过滤器配置了/*,可以拦截任何资源。
拦截器只会对控制器中的方法进行拦截。
拦截器也是AOP思想的一种实现方式
想要自定义拦截器,需要实现HandlerInterceptor接口。
2.配置拦截器
1.编写拦截器类
public class MyInterceptor implements HandlerInterceptor {
//预处理,controller方法执行前
//return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器先执行11111111111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
//后处理方法,controller方法执行后,success.jsp执行之前
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后1111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
//success.jsp页面执行后,该方法会执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后1111");
}
}
2.配置
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="com.itheima.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
tem.out.println(“MyInterceptor1执行了…后1111”);
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
//success.jsp页面执行后,该方法会执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后1111");
}
}
2.配置
~~~xml
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="com.itheima.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>