三层架构和mvc设计模式
-
三层架构
-
表现层: 接收请求响应用户
servlet – springMVC -
业务层:处理业务,事务
自己写业务层 – spring 管理业务层 -
持久层: 对数据库进行增删改查操作
jdbc – dbutils --jdbcTemplate – mybatis – spring data
-
-
MVC设计模式
-
M:model 模型:封装数据
广义:业务模型层 = dao + service + domain -
V:view 视图:展示数据
广义:能展示数据都是视图:jsp, html ,pdf ,freemarker -
controller: 控制层:接收请求响应用户
-
mvc框架要做哪些事情
回顾servlet
<dependencies>
<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>
</dependencies>
<?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">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- <session-config>-->
<!--<!– session超过15min就会超时–>-->
<!-- <session-timeout>15</session-timeout>-->
<!-- </session-config>-->
<!-- <welcome-file-list>-->
<!--<!– 欢迎页,默认就是 index.jsp–>-->
<!-- <welcome-file>index.jsp</welcome-file>-->
<!-- </welcome-file-list>-->
</web-app>
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取前端参数
String method = req.getParameter("method");
if (method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if (method.equals("delete")){
req.getSession().setAttribute("msg","执行了delete方法");
}
// 2. 调用业务层
// 3. 视图转发或者重定向
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
// resp.sendRedirect();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
<%--
Created by IntelliJ IDEA.
User: EDY
Date: 2023/12/26
Time: 10:00
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>
<form action="/hello" method="post">
<input type="text" name="method">
<input type="submit">
</form>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: EDY
Date: 2023/12/26
Time: 9:53
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>
${msg}
</body>
</html>
初识springmvc
springmvc是spring framework的一部分,是基于java实现mvc的轻量级web框架。
spring是一个大杂烩,我们可以将springmvc中所有要用到的bean,注册到spring中!
- 不同的处理器:类和方法
我们之前使用servlet是创建了很多servlet的,通过调用service、dao、数据库最终再返回给用户jsp页面
很多servlet就是个问题,我们就在中间加一层调度
,负责处理请求、适配url、跳转页面等功能,这就是DispatcherServlet
的作用。
之前我们需要创建很多servlet,在使用springmvc之后就只需要添加几个方法即可。
springmvc的执行原理
- 前端控制器:DispatcherServlet
- 请求处理器:一段儿java程序
- 模型:service、dao、pojo
- modelAndView:携带视图和model的信息交给前端控制器
虚线的地方是需要我们做的,实线的地方都是由springmvc帮我们做的
- HandlerMapping处理器映射器:建立地址与方法的映射,HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
- HandlerAdapter处理器适配器:根据地址调用方法
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。 - ViewResolver 视图解析器:处理ModelAndView数据和视图
根据handler返回的view地址文件类型(jsp/pdf….)去寻找相应的视图解析器来进行解析
简要分析springmvc执行流程
springMvc的执行流程(原理2)
- 用户发送请求至前端控制器DispatcherServlet。
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器。
- 执行处理器(Controller层,也叫后端控制器)。
- Controller执行完成返回数据和视图(ModelAndView)。
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
- ViewReslover解析后返回具体的View视图(JSP / HTML)。
- DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet响应用户,用户看到界面和数据。
总结流程
Spring MVC所有的请求都经过DispatcherServlet来统一分发
。
DispatcherServlet将请求分发给Controller之前,需要借助于Spring MVC提供的HandlerMapping定位到具体的Controller
。
HandlerMapping接口负责完成客户请求到Controller映射。
Controller接口将处理用户请求,这和Java Servlet扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView(数据和视图)对象给DispatcherServlet前端控制器。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
返回的视图需要通过ViewResolver接口(视图解析器)在Web应用中负责查找View对象,从从而将相应结果渲染给客户。
code
<?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">
<!-- 配置DispatcherServlet:这个是springmvc的核心:前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet绑定spring的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
启动级别:1
由于系统刚启动有些请求就会被处理了,所以我们让它和服务器一起启动
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
/:只匹配所有的请求,不会去匹配jsp页面
/*:匹配所有的请求和jsp页面
jsp页面应该是直接返回给客户的,但是使用/*,视图解析器就会在.jsp后面再加一个.jsp
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
=================== springmvc的核心三大组件 =====================
实际开发中并不需要配置,这里为了学习
-->
<!-- 处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--
视图解析器实际中也需要配置
模板引擎 Thymeleaf Freemarker
-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--
BeanNameUrlHandlerMapping:这个处理映射器会根据bean的id来匹配路径
-->
<bean id="/hello" class="com.lx.controller.HelloController"/>
</beans>
package com.lx.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
// 业务代码
// 添加返回的数据,model
modelAndView.addObject("msg","success");
// 视图跳转
modelAndView.setViewName("test");
return modelAndView;
}
}
springmvc常用知识
- springmvc post乱码解决
- springmvc 核心配置文件
- springmvc 参数绑定
- springmvc controller返回值
<?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">
<!-- 配置DispatcherServlet:这个是springmvc的核心:前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet绑定spring的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
启动级别:1
由于系统刚启动有些请求就会被处理了,所以我们让它和服务器一起启动
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
/:只匹配所有的请求,不会去匹配jsp页面
/*:匹配所有的请求和jsp页面
jsp页面应该是直接返回给客户的,但是使用/*,视图解析器就会在.jsp后面再加一个.jsp
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决springmvc post乱码问题-->
<filter>
<filter-name>encodingFilter</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>
<!-- 所有的请求必须先通过CharacterEncodingFilter过滤,再进入其他Filter。-->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
<?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
https://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.lx.controller"/>
<!--
支持mvc注解驱动
在spring中一般采用@Requestmapping注解来完成映射关系,要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping(处理器映射器)和
AnnotationMethodAdapter(处理适配器)实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven帮助我们自动完成上述两个实例的注入
-->
<!--mvc的注解驱动,可以自动加载处理映射器,处理适配器-->
<!--注解驱动可以加载springMVC的丰富的功能: 自定义类型转换器, ajax 技术必须引入注解驱动-->
<mvc:annotation-driven>
<!-- json乱码问题配置-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--
让springmvc不处理静态资源 .css .js .html .mp3
这些资源不需要走视图解析
-->
<mvc:default-servlet-handler/>
<!--对静态资源放行-->
<!--把js下的文件映射到js目录下-->
<!-- <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>-->
<!--配置内部资源视图解析器-->
<!--拼接:/WEB-INF/show.jsp -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
package com.lx.controller;
import com.lx.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// @Controller代表这个类会被spring接管,其中所有的方法如果返回值是String,并且有具体的页面可以跳转
// 那么就会被视图解析器解析
@Controller
public class HelloController {
/**
* ==================================== 初识demo ======================================
* 返回字符串 直接找视图解析器进行拼接页面
* @param model
* @return
*/
@RequestMapping("hello")
public String hello(Model model){
model.addAttribute("msg","success");
return "hello";
}
/**
* ============================================ 参数的绑定 ========================================
* 简单类型
* 方法的参数名与表单属性名一致,即可获取
*
* pojo类型
* 只要实体类的属性名与表单属性名一致,即可获取
*
* 表单中属性名name映射到方法参数username
* @RequestParam(“name”) String username;
*
* required:是否必要参数,默认为true
* defaultValue:默认值,优先使用传递的参数
* @param id
* @param model
* @return
*/
@GetMapping("testPathVariable/{id}")
// @PostMapping
public String testPathVariable(@PathVariable("id") String id, Model model){
model.addAttribute("msg",id);
return "hello";
}
@RequestMapping("testRequestParam")
public String testRequestParam(@RequestParam("id") String id, Model model){
model.addAttribute("msg",id);
return "hello";
}
@RequestMapping("testRequestParamPojo")
public String testRequestParamPojo(User user,HttpServletResponse response,Model model) throws IOException {
// http://localhost:8080/testRequestParamPojo?name=zs&age=4&sex=0
model.addAttribute("msg",user);
return "hello";
}
// ==============================springmvc中也可以使用request和response=================================
@RequestMapping("testHttpServletRequest")
public String testHttpServletRequest(HttpServletRequest request, HttpServletResponse response,Model model){
model.addAttribute("msg",request.getSession().getId());
return "hello";
}
// ===============================不同的返回值跳转的页面=========================================
/**
*
* 返回void 则拼接请求路径
* 请求路径为 /controller/page/{1} 访问的页面为 /WEB-INF/jsp/controller/page/1.jsp
*
* 返回string
* 视图解析器直接拼接
*
* 使用全路径
* 返回值从 /WEB-INF 开始
*
* 使用 ModelAndView
*
* forward和redirect不走视图解析器
* WEB-INF目录只可以forward,不能redirect
*
*
* @param request
* @param response
* @param model
* @return
*/
@RequestMapping("testForward1")
public String testForward(HttpServletRequest request, HttpServletResponse response,Model model){
// 测试请求转发需要注释掉 视图解析器
// forward和redirect不注释视图解析器也生效,直接 / 就会变成 .jsp.jsp
model.addAttribute("msg","testForward1");
// 返回值加 / 就是不通过视图解析器
return "/WEB-INF/jsp/testReturnPath.jsp";
// 相当于用了原生的servlet
// request.setAttribute("msg","testForward");
// request.getRequestDispatcher("/WEB-INF/jsp/test.jsp");
}
@RequestMapping("testForward2")
public String testForward2(HttpServletRequest request, HttpServletResponse response,Model model){
model.addAttribute("msg","testForward2");
return "forward:/WEB-INF/jsp/testReturnPath.jsp";
}
@RequestMapping("testRedirect")
public String testRedirect(HttpServletRequest request, HttpServletResponse response,Model model){
model.addAttribute("msg","testRedirect");
// http://localhost:8080/testRedirect 就会变成
// http://localhost:8080/index.jsp?msg=testRedirect
return "redirect:/index.jsp";
}
/**
*
* ==================================解决springmvc post请求乱码问题=========================================
* 处理前端乱码问题,就是前端form表单填中文提交之后,后端再回显给页面这个时候就会出现乱码
* post请求是乱码的,get请求不会
* 在web.xml中配置filter
*
* 过滤器解决乱码
* @param name
* @param model
* @return
*/
@RequestMapping("messyCode")
public String messyCode(@RequestParam("name") String name,Model model){
model.addAttribute("msg",name);
return "hello";
}
}
<%--
Created by IntelliJ IDEA.
User: EDY
Date: 2023/12/28
Time: 19:48
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>
<form action="/messyCode" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
springmvc 相关知识
restful风格
json
jackson和fastjson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
package com.lx.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.lx.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
//@Controller 会走视图解析器
@RestController // 该类的所有方法都不会走视图解析器,全部返回字符串
public class UserController {
/**
* @ResponseBody 不走视图解析器 将返回的java对象解析成json
*
*
* 当controller的方法标记@ResponseBody或者Controller标记@RestController注解后,会用解析器去解析Controller的返回值,
* 解析器会去搜索SpringMVC中注册的HttpMeesageConverter接口的实现类,如果没有添加对应的依赖,就会报出找不到Json类型的转换器异常
*
* 如果是Springboot项目的话,不用这么麻烦,因为你只需要添加web的启动依赖即可,不要再额外添加解析器的依赖,以为springboot都做了底层的依赖管理
*
* @return
*/
// produces = "application/json;charset=utf-8" 解决前端乱码,但是每个请求都需要这么配置就很烦
// 我们只需要在配置文件中配置即可
@RequestMapping(value = "jacksonTest")
// @ResponseBody
public String jacksonTest() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("林朝夕", "17", "女");
String s = objectMapper.writeValueAsString(user);
return s;
}
@RequestMapping(value = "jacksonTestList")
public String jacksonTestList() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
List<User> userList = new ArrayList<>();
User user1 = new User("林朝夕", "17", "女");
User user2 = new User("东野圭吾", "50", "男");
userList.add(user1);
userList.add(user2);
String s = objectMapper.writeValueAsString(userList);
return s;
}
@RequestMapping(value = "jacksonTestDate")
public String jacksonTestDate() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
// 默认是生成时间戳的,false代表不用默认的
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
// 第一种方式,使用LocalDate直接格式化
// LocalDateTime localDateTimeNow = LocalDateTime.now();
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// String string = formatter.format(localDateTimeNow);
// 第二种,使用jackson来格式化日期 老师用的是Date类,localDateTimeNow在这儿并不生效
// 使用localdatetime 返回的还是它本身,
// {"month":"JANUARY","year":2024,"dayOfMonth":4,"hour":14,"minute":51,"monthValue":1,"nano":826000000,"second":29,
// "dayOfWeek":"THURSDAY","dayOfYear":4,"chronology":{"id":"ISO","calendarType":"iso8601"}}
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
LocalDateTime localDateTimeNow = LocalDateTime.now();
// "2024-01-04 14:41:45"
String s = objectMapper.writeValueAsString(localDateTimeNow);
return s;
}
@RequestMapping(value = "fastJsonTest")
public String fastJsonTest() {
List<User> userList = new ArrayList<>();
User user1 = new User("林朝夕", "17", "女");
User user2 = new User("东野圭吾", "50", "男");
userList.add(user1);
userList.add(user2);
System.out.println("============================================================");
System.out.println("--------java对象转json字符串--------");
// {"age":"17","name":"林朝夕","sex":"女"}
System.out.println(JSON.toJSONString(user1));
// [{"age":"17","name":"林朝夕","sex":"女"},{"age":"50","name":"东野圭吾","sex":"男"}]
System.out.println(JSON.toJSONString(userList));
System.out.println("-------------json字符串转java对象-----------");
// User(name=林朝夕, age=17, sex=女)
System.out.println(JSON.parseObject(JSON.toJSONString(user1),User.class));
System.out.println("-----------java对象转json对象----------");
// 林朝夕
System.out.println(((JSONObject)JSON.toJSON(user1)).getString("name"));
System.out.println("-----------json对象转java对象----------");
// User(name=林朝夕, age=17, sex=女)
System.out.println(JSON.toJavaObject((JSONObject)JSON.toJSON(user1),User.class));
return JSON.toJSONString(userList);
}
}
springmvc spring mybatis整合
以下代码只需要关注服务端即可
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_day03</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--mybatis 与 spring 整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--spring数据源-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
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>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--post请求编码过滤器-->
<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>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置servlet-->
<!--配置前端控制器:核心控制类(springmvc已经创建好),就是一个servlet-->
<!--前端控制器创建的是 spring ioc 子容器
父容器中的对象可以直接使用
子容器中的对象,父容器不能使用
子容器中的对象,其他子容器也不能使用
-->
<!--创建父容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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:spring-mvc.xml,classpath:applicationContext.xml</param-value>
</init-param>
<!--配置的servlet的创建的顺序, 在启动tomcat时即会创建-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!-- 拦截所有的请求和静态资源(js,css,img,插件)-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring与mybatis整合的配置文件
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"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--dao层-->
<!--引入属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置spring数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 创建sqlSessionFactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.itheima.domain"></property>
</bean>
<!--扫描dao层的包,创建动态代理对象,并存入spring ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.dao"></property>
</bean>
<!--service层-->
<context:component-scan base-package="com.itheima.service"></context:component-scan>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*"></tx:method>
</tx:attributes>
</tx:advice>
<!--aop配置,织入-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution( * com.itheima.service.impl.*.*(..))"></aop:advisor>
</aop:config>
</beans>
springmvc 配置文件
spring-mvc.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
https://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="com.itheima.controller"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/fonts/**" location="/fonts/"></mvc:resources>
<!--<!–把控制器作为servlet处理,不拦截静态资源–>-->
<!--<mvc:default-servlet-handler></mvc:default-servlet-handler>-->
</beans>
mybatis 映射文件
<?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.itheima.dao.AccountDao">
<select id="findAll" resultType="account">
select * from account
</select>
<select id="findById" parameterType="int" resultType="account">
select * from account WHERE id = #{id}
</select>
<insert id="save" parameterType="account">
INSERT INTO account (name,money) VALUES (#{name},#{money})
</insert>
<update id="update" parameterType="account">
UPDATE account SET name = #{name},money = #{money} WHERE id = #{id}
</update>
<delete id="deleteById" parameterType="int">
DELETE FROM account WHERE id = #{id}
</delete>
</mapper>
controller 层
package com.itheima.controller;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public ModelAndView findAll(){
List<Account> accountList = accountService.findAll();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("accountList",accountList);
modelAndView.setViewName("show");
return modelAndView;
}
@RequestMapping("/save")
public String save(Account account){
accountService.save(account);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("show");
return "redirect:/account/findAll";
}
@RequestMapping("/del")
public String del(Integer id){
accountService.deleteById(id);
return "redirect:/account/findAll";
}
@RequestMapping("/updateUI")
public ModelAndView updateUI(Integer id){
Account account = accountService.findById(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("account",account);
modelAndView.setViewName("update");
return modelAndView;
}
@RequestMapping("/update")
public String update(Account account){
accountService.update(account);
return "redirect:/account/findAll";
}
}
service层
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public List<Account> findAll() {
return accountDao.findAll();
}
public Account findById(Integer id) {
return accountDao.findById(id);
}
public List<Account> findByName(String name) {
return accountDao.findByName(name);
}
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account) {
accountDao.update(account);
}
public void deleteById(Integer id) {
accountDao.deleteById(id);
}
}
dao层
package com.itheima.dao;
import com.itheima.domain.Account;
import java.util.List;
public interface AccountDao {
List<Account> findAll();
Account findById(Integer id);
List<Account> findByName(String name);
void save(Account account);
void update(Account account);
void deleteById(Integer id);
}
前端主要是使用jsp
展示页面
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- 引入CSS样式 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
</head>
<body>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<a class="btn btn-default" href="${pageContext.request.contextPath}/pages/save.jsp">添加</a>
</div>
<!-- Table -->
<table class="table">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>money</th>
</tr>
</thead>
<tbody>
<c:forEach items="${accountList}" var="item">
<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.money}</td>
<td>
<%--点击事件也可以--%>
<a href="javascript:del(${item.id})" class="btn btn-danger">删除</a>
<a href="${pageContext.request.contextPath}/account/updateUI?id=${item.id}" class="btn btn-info">修改</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
<!-- 引入JS文件 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.9.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
<script type="text/javascript">
function del(id){
if(confirm("您确定要删除么?")){
location.href = "${pageContext.request.contextPath}/account/del?id=" + id
}
}
</script>
</html>
保存页面
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- 引入CSS样式 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
</head>
<body>
<div class="panel panel-default">
<!-- Default panel contents -->
<form class="form-horizontal" role="form" action="${pageContext.request.contextPath}/account/save">
<div class="form-group">
<label for="accountName" class="col-sm-2 control-label">账户名</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="accountName" name="name"
placeholder="请输入账户名">
</div>
</div>
<div class="form-group">
<label for="balance" class="col-sm-2 control-label">余额</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="balance" name="money"
placeholder="请输入余额">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">保存</button>
</div>
</div>
</form>
<!-- Table -->
</div>
</body>
<!-- 引入JS文件 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.9.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</html>
更新页面
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- 引入CSS样式 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
</head>
<body>
<div class="panel panel-default">
<!-- Default panel contents -->
<form class="form-horizontal" role="form" action="${pageContext.request.contextPath}/account/update">
<div class="form-group">
<label for="accountName" class="col-sm-2 control-label">账户名</label>
<div class="col-sm-10">
<input type="hidden" name="id" value="${account.id}" ></input>
<input type="text" class="form-control" id="accountName" value="${account.name}" name="name"
placeholder="请输入账户名">
</div>
</div>
<div class="form-group">
<label for="balance" class="col-sm-2 control-label">余额</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="balance" value="${account.money}" name="money"
placeholder="请输入余额">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">保存</button>
</div>
</div>
</form>
<!-- Table -->
</div>
</body>
<!-- 引入JS文件 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.9.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</html>
springmvc拦截器
- 过滤器是会拦截静态资源的(拦截器看下面的配置的话也是可以配置拦截静态资源的,所以这个区别有待商榷 todo)
过滤器的用处:
- 在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest;
根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 头和数据; - 在 HttpServletResponse 到达客户端之前,拦截 HttpServletResponse;
根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse头和数据。
Spring 的 Interceptor(拦截器)与 Servlet 的 Filter 有相似之处,比如二者都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。
不同之处总结如下:
1、拦截器是基于java的反射机制的,而过滤器是基于函数回调。
2、拦截器是属于springmvc的,过滤器是属于servlet的。
3、filter只在servlet前后起作用,拦截器能够深入到方法前后、异常抛出前后等,具有更大的弹性。
在spring中,优先使用拦截器,它几乎可以实现过滤器的所有功能。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springmvc_day03</groupId>
<artifactId>interceptor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
</project>
<?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
https://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="com.itheima.controller"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/fonts/**" location="/fonts/"></mvc:resources>
<!--配置拦截器链-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截所有的请求,包括静态资源-->
<mvc:mapping path="/**"/>
<!--指定拦截器类-->
<mvc:exclude-mapping path="/css/**"></mvc:exclude-mapping>
<mvc:exclude-mapping path="/js/**"></mvc:exclude-mapping>
<mvc:exclude-mapping path="/fonts/**"></mvc:exclude-mapping>
<bean class="com.itheima.controller.interceptor.InterceptorFirst"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!--拦截所有的请求,包括静态资源-->
<mvc:mapping path="/**"/>
<!--指定拦截器类-->
<mvc:exclude-mapping path="/css/**"></mvc:exclude-mapping>
<mvc:exclude-mapping path="/js/**"></mvc:exclude-mapping>
<mvc:exclude-mapping path="/fonts/**"></mvc:exclude-mapping>
<bean class="com.itheima.controller.interceptor.InterceptorSecond"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
package com.itheima.controller.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class InterceptorFirst implements HandlerInterceptor {
/**
* 在控制器方法执行前执行
*
* 作用
* 在操作之前进行验证
*
* 顺序
* 按照配置顺序执行
*
*
* 应用
*
* 判断是否登录了
* 如果不存在登录信息,回到登录页面
* 如果存在登录信息,则放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
if (requestURI.contains("login")){
// 放行
return true;
}else {
response.sendRedirect("login.jsp");
return false;
}
}
/**
* 控制器方法返回值之前执行
* 所有的preHandle都返回true才会执行
*
* 顺序
* 按照配置顺序倒序执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("first postHandle");
}
/**
*
* 控制器方法返回值后,页面渲染完成后执行
* 所有的preHandle都返回true才会执行
*
*顺序
* 按照配置顺序倒序执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("first afterCompletion");
}
}
自定义类型转换器
参数是特殊类型,例如Date
package com.itheima.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 转换之前是String,转换之后是Date
*/
public class StringToDateConverter implements Converter<String,Date> {
@Override
public Date convert(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
Date data = simpleDateFormat.parse(s);
return data;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
配置文件
<?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="com.itheima"></context:component-scan>
<bean id="conversionService" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--关联类型转换器工厂-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--创建类型转换器工厂-->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
</beans>
springmvc的文件上传
<%--
Created by IntelliJ IDEA.
User: EDY
Date: 2023/12/28
Time: 19:28
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>
$END$
<form action="${pageContext.request.contextPath}/user/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file" />
<input type="submit">
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>springmvc_study Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</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>5.0.2.RELEASE</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<!--文件上传的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<build>
<finalName>springmvc_study</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
<?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
https://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="com.itheima"></context:component-scan>
<!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!--<property name="prefix" value="/WEB-INF/"></property>-->
<!--<property name="suffix" value=".jsp"></property>-->
<!--</bean>-->
<!--<!–创建类型转换器工厂–>-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!--<!–关联类型转换器工厂–>e-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--对静态资源放行-->
<!--把js下的文件映射到js目录下-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<!--文件上传解析器-->
<!--id值是固定的-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置文件上传的最大尺寸为5m-->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
</beans>
package com.itheima.controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/upload")
public String saveSesion(String username, MultipartFile upload, HttpServletRequest request) {
// 获取唯一的文件名称 -- uuid
String uuidName = UUID.randomUUID().toString().replace("-", "");
// 获取扩展名
// 获取原始的文件名
String originalFilename = upload.getOriginalFilename();
String extendName = originalFilename.substring(originalFilename.lastIndexOf("."));
// 传到服务器上的文件名称
String fileName = uuidName + extendName;
// 获取服务器的路径
// 获取upload在服务器上的绝对路径
String uploadPath = request.getSession().getServletContext().getRealPath("upload");
// 判断路径是否存在
if (!new File(uploadPath).exists()){
new File(uploadPath).mkdirs();
}
try {
upload.transferTo(new File(uploadPath + "/" + fileName));
} catch (IOException e) {
e.printStackTrace();
}
return "show";
}
}
跨服务器上传
有专门处理图片的服务器
在上面服务的代码,再次创建一个服务
测试的时候用的是tomcat,需要修改tomcat的conf/web.xml,readonly为false
这个服务是空的,只在webapp下创建一个文件夹和一个文件即可,下面的代码都是上面那个服务器的
添加依赖
<!--引入jersey服务器的包-->
<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>
修改代码
package com.itheima.controller;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/upload")
public String saveSesion(String username, MultipartFile upload, HttpServletRequest request) {
// 获取唯一的文件名称 -- uuid
String uuidName = UUID.randomUUID().toString().replace("-", "");
// 获取扩展名
// 获取原始的文件名
String originalFilename = upload.getOriginalFilename();
String extendName = originalFilename.substring(originalFilename.lastIndexOf("."));
// 传到服务器上的文件名称
String fileName = uuidName + extendName;
// 获取服务器的路径
// 获取upload在服务器上的绝对路径
String url = "http://localhost:9090/imgserver/upload";
// 跨服上传
// 创建客户端
Client client = Client.create();
// 获取服务器资源
WebResource resource = client.resource(url + "/" + fileName);
// 开始上传
try {
resource.put(String.class,upload.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return "show";
}
}
springmvc统一处理异常
public class CustomException extends Exception{
private String message;
public CustomException( String message) {
super(message);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
@Component
public class HandlerResolver implements HandlerExceptionResolver {
/**
* 在控制层出现了都会进入该方法执行
* 所以service和dao层的异常都可以往上抛
* @param request 请求对象
* @param response 响应对象
* @param handler 处理器
* @param exception 异常对象
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
//打印异常信息
exception.printStackTrace();
//创建一个自定义异常类
CustomException customException = new CustomException("系统错误,请于管理员联系,谢谢配合!!!!");
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
//添加数据
modelAndView.addObject("customException",customException);
//指定页面
modelAndView.setViewName("error");
return modelAndView;
}
}
系统日志功能
实体类
public class SysLog {
private Long id;
private String visitTime;
private String username;
private String ip;
private String method;
//此处省略getter和setter方法... ...
}
springmvc.xml配置文件中开启aop的自动代理
<!--aop的自动代理
其中proxy-target-class设置为true代表目标类的代理对象不需要借助于接口
即使用cglib基于子类生成目标对象的代理对象
-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
在web.xml中配置监听request对象的监听器
<!--配置请求监听器:当请求发生时,在容器中创建请求对象-->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
编写切面类(切面类内部有增强)
package com.itheima.log;
import com.itheima.domain.Log;
import com.itheima.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* aop: 切面 = 增强(通知) + 切入点
* 增强:对真实方法的增强部分
* 增强类型:前置增强,后置增强,异常增强,最终增强,环绕增强(必须执行目标对象的方法, 必须返回原始方法的返回值)
* 切入点:对连接点的定义
* 连接点:被拦截的方法, 在spring只有方法才是连接点
* 目标对象:target, 真实对象
* 织入:把切入点与增强关联
*
* 以此类为切面类
* controller中的方法为连接点
*
* @Aspect: 标记该类为切面类
* @Component: 创建该类对象
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
@Aspect
@Component
public class LogController {
@Autowired
LogService logService;
@Autowired
HttpServletRequest request;
/**
* 切入点声明
*/
@Pointcut("execution(* com.itheima.controller.*.*(..))")
public void pc(){}
/**
* 前置增强
*
* 获取日志信息,并保存到数据库
*/
@Before("pc()")
public void before(JoinPoint joinPoint){
Log log = new Log();
//获取日志信息
// 访问者用户名 private String username;
//获取上下文对象
SecurityContext securityContext = SecurityContextHolder.getContext();
//获取认证对象
Authentication authentication = securityContext.getAuthentication();
//获取用户对象
User user = (User) authentication.getPrincipal();
//获取用户名
String username = user.getUsername();
log.setUsername(username);
//访问时间 private Date visitTime;
log.setVisitTime(new Date());
//访问者的ip地址 private String ip;
String ip = request.getRemoteAddr();
log.setIp(ip);
//访问的方法全名称 = 全类名 + 方法名 private String method;
//获取目标对象,被代理的对象,真实对象
Object target = joinPoint.getTarget();
//获取全类名
String className = target.getClass().getName();
//获取方法
Signature signature = joinPoint.getSignature();
//获取方法名称
String methodName = signature.getName();
log.setMethod(className + "." + methodName);
logService.save(log);
}
}
云朵如肮脏的棉团漂浮在前方的天空。
湖畔
东野圭吾
部分知识引用自:
https://blog.csdn.net/qq_39372821/article/details/88405196
https://blog.csdn.net/qq_40542534/article/details/109065239
https://www.cnblogs.com/lenve/p/10748453.html
https://www.bilibili.com/video/BV1aE41167Tu?p=4&vd_source=64c73c596c59837e620fed47fa27ada7