1.spring mvc
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
查看官方文档:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
1.1.三层结构
B/S架构系统标准的三层架构包括表现层、业务层和持久层,每一层各司其职, 接下来我们就说说每层都负责哪些方面。
表现层
也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。
-
表现层又包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
-
表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
-
表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
业务层:
也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。
-
web 层依赖业务层,但是业务层不依赖 web 层。
-
业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)
持久层:
也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。
通过分层更好的实现了各个部分的职责,在每一层将再细化出不同的框架,分别解决各层关注的问题。三层架构与SSM的关系示意图如下,其中SpringMVC属于表现层框架,MyBatis属于持久层框架,而Spring不属于任何一层,是用来整合其它框架的。
1.2.mvc 模型
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
Model(模型)
指的就是我们的数据模型,一般情况下用于封装数据。
View(视图)
指的就是我们的 jsp 或者 html等页面,一般用于展示数据的,其是依据模型数据创建的。
Controller(控制器)
是应用程序中处理用户交互的部分,用来处理程序逻辑的。例如参数校验等。
1.3.Spring MVC
1.3.1.特点:
-
清晰的角色划分
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
-
分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
-
由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
-
和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
-
可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
-
可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
-
功能强大的数据验证、格式化、绑定机制。
-
利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
-
本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
-
强大的 JSP 标签库,使 JSP 编写更容易。
-
还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持,数据验证、格式化、本地化、主题等等。
-
用的人多。
1.3.2.执行流程
1.4.SpringMVC 和 Struts2
共同点:
-
它们都是表现层框架,都是基于 MVC 模型编写的。
-
它们的底层都离不开原始 ServletAPI。
-
它们处理请求的机制都是一个核心控制器。
区别:
-
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
-
Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
-
Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
-
Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,尤其是 struts2 的表单标签,远没有 html 执行效率高
2.spring mvc入门demo
2.1.配置版
创建model,添加目录java,resources.
实现步骤其实非常的简单:
- 新建一个web项目
- 导入相关jar包
- 编写web.xml , 注册DispatcherServlet
- 编写springmvc配置文件
- 接下来就是去创建对应的控制类 , controller
- 最后完善前端视图和controller之间的对应
- 测试运行调试.
2.1.1.添加依赖
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--servletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.1.2.配置web.xml , 注册DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.1.3.添加资源文件springmvc-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: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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--添加 处理映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--添加 处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/page/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--将自己的类交给SpringIOC容器,注册bean-->
<!--Handler-->
<bean id="/hello" class="com.wyl.HelloController"/>
</beans>
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
2.1.4.添加软件包 com.wyl.controller,添加controller
package com.wyl.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @创建人 王延领
* @创建时间 2021/10/15
* 描述
**/
public class HelloController implements Controller{
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModeAndView
mv.addObject("msg","王延领学习java");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello");
return mv;
}
}
2.1.5. 添加映射
<!--将自己的类交给SpringIOC容器,注册bean-->
<!--Handler-->
<bean id="/hello" class="com.wyl.HelloController"/>
2.1.6.添加页面
2.1.7.tomcat运行
2.2.注解版
2.2.1.添加依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--servletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
2.2.1.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--不要web-app,不然model 返回失效-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--注册servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!--
/ 和/* 的区别:
< url-pattern > / </ url-pattern >
不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。
< url-pattern > /* </ url-pattern >
会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.2.3.添加资源文件springmvc-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: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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.wyl.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
2.2.4.添加软件包 com.wyl.controller,添加controller
package com.wyl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @创建人 王延领
* @创建时间 2021/10/18
* 描述
**/
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/sayHello")
public String hello(Model model) {
//会被视图解析器处理
return "hello";
}
}
2.1.5.添加页面
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/15
Time: 23:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
成功!!!
</body>
</html>
3.控制器
3.1.@Controller
-
@Controller注解类型用于声明Spring类的实例是一个控制器;
-
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> <context:component-scan base-package="com.wyl.controller"/>
//@Controller注解的类会自动添加到Spring上下文中 @Controller public class ControllerTest2{ //映射访问路径 @RequestMapping("/t2") public String index(Model model){ //Spring MVC会自动实例化一个Model对象用于向视图中传值 model.addAttribute("msg", "ControllerTest2"); //返回视图位置 return "test"; } }
3.2.@RequestMapping
3.2.1.RequestMapping注解:
* 作用:
* 用于建立请求URL和处理请求方法之间的对应关系
* 它可以作用在方法、类上
* 作用来类上:作用在类上时,类上的路径作为一级目录
* 在访问方法时需要加类上的路径
* 作用在方法上:指定这个方法要拦截处理哪个URL请求
* 属性:
* value:与path属性的作用是相同的,当只有value一个属性时,属性可以省略,直接写属性值
* path:与value属性作用一致,用于指定请求的URL
* method:用于指定请求的方式,比如POST、GET等使用RequestMethod枚举
* params:用于指定限制请求参数的条件,它支持简单的表达式
* 要求请求参数的key和value必须和配置的一模一样
* headers:用于指定限制请求消息头的条件
@Controller
@RequestMapping("/User")
public class RequestMappingDemoController {
@RequestMapping("SetView")
public String SetView(){
System.out.println("Hello SpringMvc");
//返回逻辑视图名
return "success";
}
//类上加了@RequestMapping注解后,此方法拦截的URL变成了:user/testRequestMapping
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
System.out.println("测试RequestMapping注解。。");
//返回逻辑视图名
return "success";
}
//指定此方法只能由POST请求访问
@RequestMapping(path = {"/testRequestMappingMethod"},method = {RequestMethod.POST})
public String testRequestMappingMethod(){
System.out.println("测试RequestMapping注解的method属性。。");
//返回逻辑视图名
return "success";
}
//指定此方法必须带有name属性,且属性值必须为admin
//http://localhost:8080/User/testRequestMappingParams?name=admin
@RequestMapping(path = {"/testRequestMappingParams"},params = {"name=admin"})
public String testRequestMappingParams(){
System.out.println("测试RequestMapping注解的params属性。。");
//返回逻辑视图名
return "success";
}
//指定请求头中必须包含accept属性
@RequestMapping(path = {"/testRequestMappingHeaders"},headers = {"accept"})
public String testRequestMappingHeaders(){
System.out.println("测试RequestMapping注解的headers属性。。");
//返回逻辑视图名
return "success";
}
}
3.2.2.RestFul风格
//映射访问路径
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1+p2;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果:"+result);
//返回视图位置
return "test";
}
-
REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
-
它本身并没有什么实用性,其核心价值在于如何设计出符合REST风格的网络接口。
-
restful的优点 :
- 它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
-
restful的特性:
-
资源(Resources):
- 网络上的一个实体,或者说是网络上的一个具体信息。 它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要 获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
-
表现层(Representation):
- 把资源具体呈现出来的形式,叫做它的表现层 (Representation)。 比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
-
状态转化(State Transfer):
- 每 发出一个请求,就代表了客户端和服务器的一次交互过程。 HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
-
3.2.3.组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一个组合注解@RequestMapping(method =RequestMethod.GET) 的一个快捷方式
//原来的:http://localhost:8080/add?a=1&b=2
//RestFul风格:http://localhost:8080/add/a/b
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model) {//@PathVariable路径变量
int res = a + b;
model.addAttribute("msg", "结果为:" + res);
return "test";
}
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.Post)
@PostMapping("/add/{a}/{b}")
public String test2(@PathVariable int a, @PathVariable int b, Model model) {//@PathVariable路径变量
int res = a + b;
model.addAttribute("msg", "结果为:" + res);
return "test";
}
3.3.结果跳转
3.3.1.ModelAndView
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
对应controller
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ModelAndView 返回!!!");
mv.setViewName("test");
return mv;
}
}
3.3.2.ServletAPI
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
3.3.3.SpringMVC
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.
可以重定向到另外一个请求实现 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:hello.do";
}
}
3.4.处理提交数据
3.4.1.提交的域名称和处理方法的参数名一致
提交数据 : http://localhost:8080/hello?name=wyl
处理方法 :
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "test";
}
3.4.2.提交的域名称和处理方法的参数名不一致
提交数据 : http://localhost:8080/hello?username=wyl
处理方法 :
/**
* 请求参数绑定
* 请求的参数中如果有username属性的话,
* SpringMVC会自动将参数传入与方法参数列表对应的入参中
* @return
*/
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
System.out.println(name);
return "test";
}
3.4.3.提交的是一个对象
要求提交的表单域和对象的属性名一致 , 参数使用对象即可
1、实体类
public class User {
private int id;
private String name;
private int age;
//构造
//get/set
//tostring()
}
2、提交数据 : http://localhost:8080/mvc04/user?name=wyl&id=1&age=18
3、处理方法
/**
*1、接收到的前端用户传递参数,判断参数的名字,假设名字直接在方法上,可以直接使用
*2、假设传递的是一个对象user,就会匹配user对象的字段名;如果字段一致则OK,否则匹配不到
*/
@RequestMapping("/user")
public String user(User user){
System.out.println(user);
return "hello";
}
3.3.4.获取原生ServletAPI对象
提交数据 : http://localhost:8080/hello?username=wyl&password=123456
处理方法
/**
* 获取原生ServletAPI对象
* 需要哪个对象,在方法入参处定义就好了
* @param request
* @param response
* @return
*/
@RequestMapping("/hello")
public String hello(HttpServletRequest request, HttpServletResponse response){
System.out.println("获取原生ServletAPI对象。。。");
System.out.println("request:"+request);
System.out.println("从request对象中获取的用户名:"+request.getParameter("username"));
System.out.println("从request对象中获取的密码:"+request.getParameter("password"));
System.out.println("response:"+response);
System.out.println("session:"+request.getSession());
System.out.println("application:"+request.getSession().getServletContext());
//返回逻辑视图名
return "success";
}
3.5.返回结果
3.5.1.ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ModelAndView");
mv.setViewName("test");
return mv;
}
}
3.5.2.ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
3.5.3.Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
4.异常处理
4.1.异常处理的思路
系统中异常包括两类: 预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller 出现都通过throws Exception 向上抛出,最后由springmvc 前端控制器交由异常处理器进行异常处理,如下图:
4.2.编写异常类和错误页面
/**
* 自定义异常
*/
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>执行失败</title>
</head>
<body>
执行失败!
${message }
</body>
</html>
4.3.自定义异常处理器
/**
* 自定义异常处理器
*/
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
) {
ex.printStackTrace();
CustomException customException = null;
//如果抛出的是系统自定义异常则直接转换
if (ex instanceof CustomException) {
customException = (CustomException) ex;
} else {
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
customException = new CustomException("系统错误,请与系统管理 员联系!");
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", customException.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
4.4.
<!-- 配置自定义异常处理器 -->
<bean id="handlerExceptionResolver"
class="com.wyl.exception.CustomExceptionResolver" />
5.json处理
ajax我经常用到,传的数据是json数据,json数据又有对象,数组。所有总结下springmvc获取前端传来的json数据方式
5.1.Controller接受JSON数据
作用:
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端。
本例子应用:
@ResponseBody注解实现将Controller方法返回java对象转换为json响应给客户端。
5.1.1.以RequestParam接收
前端传来的是json数据不多时:[id:id],可以直接用@RequestParam来获取值
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
public String updateAttr(@RequestParam ("id") int id) {
int res=accomodationService.deleteData(id);
return "success";
}
5.1.2.以实体类方式接收
前端传来的是一个json对象时:{【id,name】},可以用实体类直接进行自动绑定
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/add")
@ResponseBody
public String addObj(@RequestBody Accomodation accomodation) {
this.accomodationService.insert(accomodation);
return "success";
}
5.1.3.以Map接收
前端传来的是一个json对象时{【id,name】},可以用Map来获取
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
public String updateAttr(@RequestBody Map<String, String> map) {
if(map.containsKey("id"){
Integer id = Integer.parseInt(map.get("id"));
}
if(map.containsKey("name"){
String objname = map.get("name").toString();
}
// 操作 ...
return "success";
}
5.1.4.以List接收
当前端传来这样一个json数组[{id,name},{id,name},{id,name},...]时,用List
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
//参数前面必须又@RequestBody
public String updateAttr(@RequestBody List<Accomodation> list) {
for(Accomodation accomodation:list){
System.out.println(accomodation.toString());
}
return "success";
}
ajax请求
var testList=[];
var user={};
user.id=1;
user.name='jack';
testList.push(user);
var user2={};
user2.id=2;
user2.name='tom';
testList.push(user2);
$.ajax({
// headers必须添加,否则会报415错误
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
type: 'POST',
dataType: "json", //表示返回值类型,不必须
data: JSON.stringify(testList),
url: '/test/postList',
success: function(){
alert('success');
}
});
需要注意点:1、参数是数组类型
2、传入data时,转换 JSON.stringify(testList)
3、必须有headers:
{ 'Accept': 'application/json',
'Content-Type': 'application/json'
}
5.2.Controller返回JSON数据
5.2.1.Jackson
Jackson应该是目前比较好的json解析工具了
当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
我们这里使用Jackson,使用它需要导入它的jar包;
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
Controller
这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法
public class UserController {
@RequestMapping("/json1")
@ResponseBody
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("wyl", 3, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
@RestController
public class UserController {
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1")
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("wyl", 3, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
抽取为工具类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object,String dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//ps:Jackson 默认是会把时间转成timestamps形式(取消timestamps形式 , 自定义时间格式)
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
demo
@RequestMapping("/jsonUnit")
public String json5() throws JsonProcessingException {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}
5.2.2.FastJson
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
fastjson 的 pom依赖!
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三个主要的类:
JSONObject 代表 json 对象
- JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
- JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
JSONArray 代表 json 对象数组
- 内部是有List接口中的方法来完成操作的。
JSON代表 JSONObject和JSONArray的转化
- JSON类源码分析与使用
- 仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
代码测试,我们新建一个FastJsonDemo 类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kuang.pojo.User;
import java.util.ArrayList;
import java.util.List;
public class FastJsonDemo {
public static void main(String[] args) {
//创建一个对象
User user1 = new User("wyl1号", 3, "男");
User user2 = new User("wyl2号", 3, "男");
User user3 = new User("wyl3号", 3, "男");
User user4 = new User("wyl4号", 3, "男");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
System.out.println("
****** JSON字符串 转 Java对象*******");
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("
****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));
System.out.println("
****** JSON对象 转 Java对象 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
}
}
6.拦截器
6.1.过滤器与拦截器的区别
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
-
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
6.2.自定义拦截器
我们要想自定义拦截器,要求必须实现HandlerInterceptor 接口。
6.2.1. 编写一个普通类实现HandlerInterceptor 接口
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
6.1.2. 配置拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.wyl.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
6.2.3.控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//测试拦截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法执行了");
return "hello";
}
}
6.2.3.前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
6.3.拦截器的细节
6.3.1. 拦截器的放行
放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
6.3.2.拦截器中方法的说明
public interface HandlerInterceptor {
/**
* preHandle方法是controller方法执行前拦截的方法,按拦截器定义顺序调用
* return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法进行业务处理。
* return false不放行,不会执行controller中的方法或调用其他的组件。
*/
default boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
return true;
}
/**
* postHandle是controller方法执行后执行的方法,在JSP视图执行前,按拦截器定义逆序调用。
* 可以使用request或者response跳转到指定的页面
* 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
*/
default void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable ModelAndView modelAndView
)
throws Exception {}
/**
* afterCompletion方法是在JSP执行后执行,按拦截器定义逆序调用
* 注意:因为结果页面已经返回完了,不能在该方法使用request或者response再跳转页面,但可以在该方法中进行一些资源清理的操作。
*/
default void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex
)
throws Exception {}
}
6.3.3. 拦截器的作用路径
作用路径可以通过在配置文件中配置。
<!-- 配置拦截器的作用范围 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" /><!-- 用于指定对拦截的url -->
<mvc:exclude-mapping path="" /><!-- 用于指定排除的url-->
<bean id="handlerInterceptorDemo1"
class="com.wyl.interceptor.HandlerInterceptorDemo1">
</bean>
</mvc:interceptor>
</mvc:interceptors>
6.3.4. 多个拦截器的执行顺序
多个拦截器是按照配置的顺序决定的。
6.3.4.1. 拦截器1 的代码
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
System.out.println("拦截器 1: preHandle 拦截器拦截了");
return true;
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
)
throws Exception {
System.out.println("拦截器 1: postHandle 方法执行了");
}
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
)
throws Exception {
System.out.println("拦截器 1: afterCompletion 方法执行了");
}
}
6.3.4.2. 拦截器2 的代码:
public class HandlerInterceptorDemo2 implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
System.out.println("拦截器2: preHandle 拦截器拦截了");
return true;
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
)
throws Exception {
System.out.println("拦截器2: postHandle 方法执行了");
}
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
)
throws Exception {
System.out.println("拦截器2: afterCompletion 方法执行了");
}
}
6.3.4.3.配置拦截器的作用范围
<mvc:interceptor>
<mvc:mapping *path*="/**" />*<!--* *用于指定对拦截的**url -->*
<bean *id*="handlerInterceptorDemo1" *class*="com.wyl.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping *path*="/**" />
<bean *id*="handlerInterceptorDemo2" *class*="com.wyl.interceptor.HandlerInterceptorDemo2"></bean>
</mvc:interceptor>
6.3.4.4.中断流程测试
拦截器2 返回false
7.上传文件
7.1.导入文件上传的jar包
<!--文件上传
commons-io 不属于文件上传组件的开发jar 文件,但Commons-fileupload 组件从1.1 版本开始,它
工作时需要commons-io 包的支持。
-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
7.2. 编写文件上传的jsp 页面
<h3>文件上传</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload" /><br />
<input type="submit" value="上传文件" />
</form>
至少有一个文件选择域
以POST方式提交
表单的enctype必须为 multipart/form-data
7.3.控制器(非SpringMVC版)
package com.wyl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}
7.4.SpringMVC配置信息
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
<!-- property name="maxUploadSize" value="10485760"/ -->
</bean>
7.5.控制器代码(SpringMVC版)
/**
* SpringMVC方式的文件上传
*/
@RequestMapping(value="/fileupload2")
public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception {
System.out.println("SpringMVC方式的文件上传...");
// 先获取到要上传的文件目录
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 创建File对象,一会向该路径下上传文件
File file = new File(path);
// 判断路径是否存在,如果不存在,创建该路径
if(!file.exists()) {
file.mkdirs();
}
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把文件的名称唯一化
filename = uuid+"_"+filename;
// 上传文件
upload.transferTo(new File(file,filename));
return "success";
}
7.6.跨服务器
准备两个tomcat 服务器,其中一个作为文件服务器,一个作为应用服务器。
7.6.1.在文件服务器tomcat的web.xml中修改tomcat配置,允许读写操作。
7.6.2.导入包
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
7.6.3.控制器
**
* SpringMVC跨服务器方式的文件上传
*/
@RequestMapping(value="/fileupload3")
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("SpringMVC跨服务器方式的文件上传...");
// 定义图片服务器的请求路径
String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把文件的名称唯一化
filename = uuid+"_"+filename;
// 向图片服务器上传文件
// 创建客户端对象(sun公司提供的jersey 包)
Client client = Client.create();
// 连接图片服务器
WebResource webResource = client.resource(path+filename);
// 上传文件 //String result = resource.put(String.class,uploadFile.getBytes());
webResource.put(upload.getBytes());
return "success";
}
7.7.下载
文件下载步骤:
1、设置 response 响应头
2、读取文件 -- InputStream
3、写出文件 -- OutputStream
4、执行操作
5、关闭流 (先开后关)
代码实现:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基础语法.jpg";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
前端
<a href="/download">点击下载</a>
测试,文件下载OK,大家可以和我们之前学习的JavaWeb原生的方式对比一下,就可以知道这个便捷多了!
拦截器及文件操作在我们开发中十分重要,一定要学会使用!
8.整合ssm
8.1.前期准备
环境:
- IDEA
- MySQL 8.0.18
- Tomcat 9
- Maven 3.6
创建数据库:
CREATE DATABASE `wyl`;
USE `wyl`;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`gender` int(255) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
8.1.项目搭建
8.1.1.创建项目
8.1.2.导入相关的pom依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- 依赖:junit,数据库驱动,连接池,servlet,jsp,mybatis,mybatis-spring,spring -->
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Servlet - JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--spring-->
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
8.1.2.静态资源导出
8.1.3.项目结构
8.1.4.配置
8.1.4.1.mybatis
database.properties(数据库配置文件)
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/wyl?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=wyl190204-
mybatis-config.xml(核心配置文件)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--转为驼峰-->
<!-- <settings>-->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>-->
<!-- </settings>-->
<!--别名-->
<typeAliases>
<package name="com.wyl.pojo"/>
</typeAliases>
<!--映射器-->
<mappers>
<mapper class="com.wyl.dao.UsersMapper"></mapper>
</mappers>
</configuration>
8.1.4.2.spring
1、配置Spring整合MyBatis,我们这里数据源使用c3p0连接池;
2、我们去编写Spring整合Mybatis的相关的配置文件;spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 1.关联数据库文件 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2.数据库连接池 -->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
<!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.wyl.dao"/>
</bean>
</beans>
spring-service.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"
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">
<!-- 扫描service相关的bean -->
<context:component-scan base-package="com.kuang.service" />
<!--BookServiceImpl注入到IOC容器中-->
<bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
8.1.4.3.spring-mvc
web.xml
<!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 xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>filter</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>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
springmvc-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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--扫描注解所在包-->
<context:component-scan base-package="com.wyl.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler/>
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven/>
<!--配置JSP视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置文件所在目录-->
<property name="prefix" value="/WEB-INF/pages/"/>
<!--配置文件的后缀名-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
8.1.1.4.整合
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="springmvc-servlet.xml"/>
</beans>
8.2.代码实现
8.2.1.pojo
package com.wyl.pojo;
import com.oracle.webservices.internal.api.databinding.DatabindingMode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @创建人 王延领
* @创建时间 2021/10/25
* 描述
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private int id;
private String username;
private String password;
private String email;
private int gender;
}
8.2.2.dao
UsersMapper.java
import com.wyl.pojo.Users;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @创建人 王延领
* @创建时间 2021/10/25
* 描述
**/
public interface UsersMapper {
//增
int addUser(Users user);
//删
int delUser(int id);
//改
int updateUser(Users user);
//查
Users queryUser(int id);
//集合
List<Users> queryUsers();
//查
List<Users> queryUserByName(String name);
}
UsersMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wyl.dao.UsersMapper">
<insert id="addUser" parameterType="Users">
insert into users(id,username,password,email,gender) values (#{id},#{username},#{password},#{email},#{gender});
</insert>
<delete id="delUser" parameterType="int">
delete from users where id=#{id}
</delete>
<update id="updateUser" parameterType="Users">
update users set username=#{username},password=#{password},email=#{email},gender=#{gender} where id=#{id}
</update>
<select id="queryUser" resultType="Users">
select * from users where id=#{id}
</select>
<select id="queryUsers" resultType="Users">
SELECT * FROM users
</select>
<select id="queryUserByName" resultType="Users">
select * from users where username like '%${name}%'
</select>
</mapper>
8.2.3.service
UsersService
package com.wyl.service;
import com.wyl.pojo.Users;
import java.util.List;
/**
* @创建人 王延领
* @创建时间 2021/10/25
* 描述
**/
public interface UsersService {
//增
int addUser(Users user);
//删
int delUser(int id);
//改
int updateUser(Users user);
//查
Users queryUser(int id);
//集合
List<Users> queryUsers();
//查
List<Users> queryUserByName(String name);
}
UsersServiceImpl
package com.wyl.service.impl;
import com.wyl.dao.UsersMapper;
import com.wyl.pojo.Users;
import com.wyl.service.UsersService;
import org.omg.CORBA.PUBLIC_MEMBER;
import java.util.List;
/**
* @创建人 王延领
* @创建时间 2021/10/25
* 描述
**/
public class UsersServiceImpl implements UsersService {
private UsersMapper userMapper;
public void setUserMapper(UsersMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public int addUser(Users user) {
int i = userMapper.addUser(user);
return i;
}
@Override
public int delUser(int id) {
int i = userMapper.delUser(id);
return i;
}
@Override
public int updateUser(Users user) {
int i = userMapper.updateUser(user);
return i;
}
@Override
public Users queryUser(int id) {
return userMapper.queryUser(id);
}
@Override
public List<Users> queryUsers() {
return userMapper.queryUsers();
}
@Override
public List<Users> queryUserByName(String name)
{
return userMapper.queryUserByName(name);
}
}
8.2.4.controller
package com.wyl.controller;
import com.wyl.pojo.Users;
import com.wyl.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Comparator;
import java.util.List;
/**
* @创建人 王延领
* @创建时间 2021/10/25
* 描述
**/
@Controller
@RequestMapping("/user")
public class UsersController {
@Autowired
@Qualifier("UsersServiceImpl")
private UsersService userService;
@RequestMapping("/userList")
public String userList(Model model) {
List<Users> users = userService.queryUsers();
users.sort(Comparator.comparingInt(Users::getId));
model.addAttribute("list", users);
return "userList";
}
@RequestMapping("/toAddUser")
public String toAddUser() {
return "addUser";
}
@PostMapping("/addUser")
public String addUser(Users user) {
System.out.println("addUser =>" + user);
int i = userService.addUser(user);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
@RequestMapping("/toUpdateUser")
public String toUpdateUser(int id, Model model) {
Users user = userService.queryUser(id);
model.addAttribute("user", user);
return "updateUser";
}
@PostMapping("/updateUser")
public String updateUser(Users user) {
System.out.println("updateUser =>" + user);
int i = userService.updateUser(user);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
@GetMapping("/deleteUser")
public String deleteUser(int id) {
System.out.println("deleteUser =>" + id);
int i = userService.delUser(id);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
/**
* 查询全部书籍,并且返回到一个书籍展示页面
*/
@RequestMapping("/byName")
public String ByName(String name, Model model) {
List<Users> users = userService.queryUserByName(name);
if (users == null || users.size() == 0) {
model.addAttribute("error", "未查询到用户");
return "userList";
}
System.out.println("users =>" + users);
// 排序
users.sort(Comparator.comparingInt(Users::getId));
model.addAttribute("list", users);
return "userList";
}
}
8.3.page
userList.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>展示页面</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>用户列表 ------ 显示所有用户</small>
</h1>
</div>
</div>
<div class="row">
<div class="col-md-4">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/user/toAddUser">新增用户</a>
</div>
<div class="col-md-2"></div>
<div class="col-md-6 right">
<form class="navbar-form navbar-right" method="get" action="${pageContext.request.contextPath}/user/byName">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name="name">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-12">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>密码</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach var="user" items="${list}">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.email}</td>
<td><a href="${pageContext.request.contextPath}/user/toUpdateUser?id=${user.id}">修改</a> | <a href="${pageContext.request.contextPath}/user/deleteUser?id=${user.id}">删除</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div>${error}</div>
</div>
</body>
</html>
aaUser.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加页面</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>新增用户</small>
</h1>
</div>
</div>
</div>
<form action="${pageContext.request.contextPath}/user/addUser" method="post">
姓名<input type="text" name="username" required><br>
密码<input type="text" name="password" required><br>
邮箱<input type="text" name="email"><br>
年龄<input type="text" name="gender"><br>
<input type="submit" value="添加">
</form>
</div>
</body>
</html>
updateUser.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>修改用户</small>
</h1>
</div>
</div>
</div>
<form action="${pageContext.request.contextPath}/user/updateUser" method="post">
<input type="hidden" name="id" value="${user.id}">
名称<input type="text" name="username" value="${user.username}"><br>
密码<input type="text" name="password" value="${user.password}"><br>
邮箱<input type="text" name="email" value="${user.email}"><br>
年龄<input type="text" name="gender" value="${user.gender}"><br>
<input type="submit" value="修改">
</form>
</div>
</body>
</html>
error.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>ERROR页面</h1>
</body>
</html>