说明:学习笔记是对B站狂神说的SpringMVC视频的整理和总结。
问题记录:maven导入jsp和jstl的时候,版本号爆红。
1、检查基本配置:idea中maven依赖爆红的排查步骤
2、最后排除出来是jar下载失败(jar包以lastUpdate结尾),我自己下载了jsp和jstl的jar,在命令行中使用maven的命令将jar包添加到maven仓库。
参考资料:将下载到本地的JAR包手动添加到Maven仓库
3、使用阿里的maven仓库有些包下载失败,原因:阿里不再支持http下载,只支持https。解决方法见参考资料:2020年解决:IDEA中已配置阿里镜像,但maven无法下载jar包的问题
MVC的概念
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
最典型的MVC就是JSP + servlet + javabean的模式。
SpringMVC的概念
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
Spring MVC的特点:
参考资料:SpringMVC官方文档5.2.0
中心控制器:DispatcherServlet 。
解释:Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
注:从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
解释:当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
上图为SpringMVC的一个较完整的执行流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
各个步骤说明如下:
http://localhost:8080/SpringMVC/hello
,如上url拆分成三部分:
http://localhost:8080
表示服务器域名通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
首先使用XML配置来创建项目,然后使用注解来创建项目,体会注解的便捷。
前提条件:添加web的支持;导入了MVC的依赖。
1、配置web.xml,主要作用是注册DispatcherServlet
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
2、编写 SpringMVC 的 配置文件springmvc-servlet.xml
说明:这里的名称要求按照官方来 [servletname]-servlet.xml
主要包括三大块(结合SpringMVC的原理来理解):
同时配置文件中需要注册bean,即将自己的类交给SpringIOC容器。
<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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
<bean id="/hello" class="com.xlq.controller.HelloController"/>
beans>
3、编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图。
package com.xlq.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 {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
// 业务代码
String result = "HelloSpringMVC";
mv.addObject("msg", result);
// 视图跳转
mv.setViewName("test");
return mv;
}
}
4、编写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
${msg}
body>
html>
5、配置并启动Tomcat进行测试。
前提条件:
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
1、配置web.xml
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
2、SpringMVC配置文件
在resource目录下添加springmvc-servlet.xml配置文件,配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:
<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.xlq.controller"/>
<mvc:default-servlet-handler />
<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>
配置文件主要内容总结:
3、创建Controller
package com.xlq.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model) {
// 封装数据
model.addAttribute("msg", "Hello, Learn SpringMVC with Annotation");
return "hello";
}
}
说明:
4、创建视图层
在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
${msg}
body>
html>
5、配置Tomcat并运行
使用springMVC必须配置的三大件:
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
作用是什么?
控制器负责解析用户的请求并将其转换为一个模型。
实现方式:
1、实现Controller接口【不推荐】
示例如下:
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "ControllerTest1");
mv.setViewName("test");
return mv;
}
}
缺点:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller。
2、使用注解@Controller【推荐】
<context:component-scan base-package="com.xlq.controller"/>
使用示例:
@Controller // 代表这个类会被Spring接管
// 被这个注解的类中的所有方法,如果返回值是String,并且有对应的页面可以跳转,那么就会被视图解析器解析
public class ControllerTest2 {
@RequestMapping("/t2")
public String test1(Model model) {
model.addAttribute("msg", "ControllerTest2");
return "test";
}
}
@RequestMapping 的作用:用于映射url到控制器类或一个特定的处理程序方法。注意:如果用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
使用示例:
@Controller
@RequestMapping("/user")
public class UserController {
// 访问路径为:localhost:8080/user/t1?name=xxx
@GetMapping("/t1") // 表示必须为get方法
public String test1(@RequestParam("username") String name, Model model) {
// 1. 接收前端参数
System.out.println("接收到前端的参数为:"+name);
// 2. 将返回的结果传递给前端, 使用Model对象
model.addAttribute("msg", name);
// 3. 视图跳转
return "test";
}
}
示例如下:
@Controller
@RequestMapping("/user")
public class UserController {
// 正常的请求URL:localhost:8080/user/t1?name=xxx
@GetMapping("/t1")
public String test1(@RequestParam("username") String name, Model model) {
// 1. 接收前端参数
System.out.println("接收到前端的参数为:"+name);
// 2. 将返回的结果传递给前端, 使用Model对象
model.addAttribute("msg", name);
// 3. 视图跳转
return "test";
}
@GetMapping("t2")
public String test2(User user) {
System.out.println(user);
return "test";
}
}
正常的请求:
http://localhost:8080/user/t1?username=xlq
http://localhost:8080/user/t2?id=1&name=xlq&age=25
注意:如果是需要前端传递过来的参数,使用注解@RequestParam来进行显式说明,并注明参数名称。这是一个好习惯。
三种方法:
ModelMap和Model的差别:
解决方法:配置SpringMVC的过滤器。
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
一般情况下,SpringMVC默认的乱码处理就已经能够很好的解决了!需要注意的其它地方:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
JSON的特点:
JSON的语法:
JSON和JavaScript的区别:JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。JSON 和 JavaScript 对象互转:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}
var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'
这里使用两个工具:
首先在pom文件中添加依赖:
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.11.0version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.72version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
实体类:
package com.xlq.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
处理JSON的工具类:
package com.xlq.utils;
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();
// 不使用时间戳的方式
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;
}
}
在控制器中使用jackson和fastjson将Java对象转为JSON字符串:
package com.xlq.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.xlq.pojo.User;
import com.xlq.utils.JsonUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody // 这个注解表明这个方法的返回值不会走视图解析器,会直接返回一个字符串
public String testJson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("xlq", 25, "男");
String str = mapper.writeValueAsString(user);
return str;
}
@RequestMapping("/j2")
@ResponseBody
public String testJson2() {
List<User> userList = new ArrayList<User>();
User user1 = new User("aaa", 18, "男");
User user2 = new User("bbb", 18, "男");
User user3 = new User("ccc", 18, "男");
userList.add(user1);
userList.add(user2);
userList.add(user3);
String json = JsonUtils.getJson(userList);
return json;
}
@RequestMapping("/j3")
@ResponseBody
public String testJson3() {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}
}
注意点:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<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>
Fastjson的使用
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便实现:
fastjson 三个主要的类:
使用示例:
@RestController
public class UserController {
@RequestMapping("j4")
public String testJson4() {
List<User> userList = new ArrayList<User>();
User user1 = new User("aaa", 18, "男");
User user2 = new User("bbb", 18, "男");
User user3 = new User("ccc", 18, "男");
userList.add(user1);
userList.add(user2);
userList.add(user3);
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(userList);
System.out.println("JSON.toJSONString(list)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
System.out.println("\n****** JSON字符串 转 Java对象*******");
User jp_user1 = JSON.parseObject(str2, User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>" + jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
return null;
}
}
主要过程梳理。
1、数据库环境:建表。
CREATE DATABASE `ssmbuild`;
USE `ssmbuild`;
DROP TABLE IF EXISTS `books`;
CREATE TABLE `books` (
`bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT(11) NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
KEY `bookID` (`bookID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');
2、IDEA工程环境
3、Mybatis层的相关内容
(1)数据库配置文件:database.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
(2)IDEA关联数据库:便于代码中涉及到数据库表结构的自动联想;
(3)编写Mybatis的核心配置文件
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<typeAliases>
<package name="com.xlq.pojo"/>
typeAliases>
<mappers>
<mapper resource="com/xlq/dao/BookMapper.xml"/>
mappers>
configuration>
(4)实体类
(5)实体类对应的Mapper接口
(6)编写接口对应的Mapper.xml文件
(7)Service调用Dao层,此时可以编写Service层的接口和实现类。(可以理解为Service层是对Dao层的包装,所以代码非常简单)
4、Spring层的相关内容
(1)配置Spring整合Mybatis,这里数据源使用c3p0;
(2)Spring整合Mybatis的相关的配置文件;spring-dao.xml
<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">
<context:property-placeholder location="classpath:database.properties"/>
<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}"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.xlq.dao"/>
bean>
beans>
(3)Spring整合service层:spring-service.xml
<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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.xlq.service"/>
<bean id="BookServiceImpl" class="com.xlq.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.xlq.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
aop:config>
beans>
5、SpringMVC层的相关内容
(1)web.xml
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
(2)spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<context:component-scan base-package="com.xlq.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
(3)Spring配置整合文件:applicationContext.xml
<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="spring-mvc.xml"/>
beans>
Controller层中调用Service层,增删改查,与前端页面实现数据交互。
Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。注意:Ajax 不是一种新的编程语言,而是一种用于创建更好、更快以及交互性更强的Web应用程序的技术。
最常见的场景:在百度的搜索框输入qq,下拉框会显示qq邮箱、qq空间、qq音乐等,此时并没有刷新整个页面而是后台根据输入的qq返回的一个结果。
Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。
这里使用jQuery提供的Ajax,避免重复造轮子。jQuery 提供多个与 Ajax 有关的方法。通过 jQuery Ajax 方法,能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON,同时能够把这些外部数据直接载入网页的被选元素中。
关于jQuery的说明:jQuery 不是生产者,而是大自然搬运工。jQuery Ajax本质就是 XMLHttpRequest,对它进行了封装,方便调用而已!
jQuery.ajax(...)
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
1、控制器层代码AjaxController.java
@RestController
public class AjaxController {
// 模拟登录提示效果
// 用户名和密码正确显示OK,错误显示提示信息
// 注意:此处的用户名和密码为固定的,正确做法是到数据库用户表中查询
@RequestMapping("/a3")
public String ajax3(String name, String pwd) {
String msg = "";
// 模拟数据库中存在数据
if (name != null) {
if ("admin".equals(name)) {
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd != null) {
if ("123456".equals(pwd)) {
msg = "OK";
}else {
msg = "密码输入错误";
}
}
return msg;
}
}
2、前端页面login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登录,模拟提示效果title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.js">script>
<script>
function a1() {
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{'name':$("#name").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#userInfo").css("color","green");
}else {
$("#userInfo").css("color","red");
}
$("#userInfo").html(data);
}
});
}
function a2(){
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{'pwd':$("#pwd").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#pwdInfo").css("color","green");
}else {
$("#pwdInfo").css("color","red");
}
$("#pwdInfo").html(data);
}
});
}
script>
head>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userInfo">span>
p>
<p>
密码:<input type="text" id="pwd" onblur="a2()"/>
<span id="pwdInfo">span>
p>
body>
html>
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
拦截器是AOP思想的具体应用。
过滤器与拦截器的区别:
/*
之后,可以对所有要访问的资源进行拦截。自定义拦截器:想要自定义拦截器,必须实现 HandlerInterceptor 接口。
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("------------清理------------");
}
}
在springmvc的配置文件中配置拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xlq.config.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
拦截器的实例:验证用户是否登录。
实现思路
登录页面:login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<%--注意:在WEB-INF下的所有页面或者资源,只能通过controller或者servlet进行访问--%>
<h1>登录页面h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
用户名:<input type="text" name="username"> <br>
密 码:<input type="text" name="password"> <br>
<input type="submit" value="提交">
form>
body>
html>
处理请求:LoginController.java
package com.xlq.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/toLogin")
public String toLogin() {
return "login";// 跳转到登录页面
}
@RequestMapping("/toMain")
public String toMain() {
return "main";// 跳转到成功页面
}
@RequestMapping("/login")
public String login(HttpSession session, String username, String password) {
System.out.println("接收前端参数:" + username + "," + password);
session.setAttribute("user", username);
return "main";
}
@RequestMapping("/goOut")
public String goOut(HttpSession session) {
session.removeAttribute("user");
return "login";
}
}
登录成功的页面:main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功title>
head>
<body>
<h1>登录成功页面h1>
${user}
<a href="${pageContext.request.contextPath}/user/goOut">注销a>
body>
html>
在index页面上测试跳转,此时点击【成功页面】能跳转成功页面,因为还没配置拦截器。正常情况下,如果用户未登录,是不能直接点击【成功页面】跳转到成功页面的,而是要跳转到登录页面,实现登录之后才能跳转到成功页面,所以要进行拦截。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$title>
head>
<body>
<h1>首页h1>
<hr>
<%--登录--%>
<a href="${pageContext.request.contextPath}/user/toLogin">登录a>
<a href="${pageContext.request.contextPath}/user/toMain">成功页面a>
body>
html>
用户登录拦截器:LoginInterceptor.java
package com.xlq.config;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在什么情况下才会放行?
// 情况一:登录页面会放行
if (request.getRequestURI().contains("toLogin")) {
return true;
}
if (request.getRequestURI().contains("login")) {
return true;
}
// 情况二:session中有内容
HttpSession session = request.getSession();
if (session.getAttribute("user") != null) {
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
在Springmvc的配置文件中注册拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.xlq.config.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
此时就可以实现所需功能。
1、导入相关依赖
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.3version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
2、配置bean:multipartResolver
SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
注意:这个bean的id必须为【multipartResolver】 , 否则上传文件会报400的错误。
3、前端表单
为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
form>
4、控制器:FileController.java
package com.xlq.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 javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@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";
}
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
}
文件下载
文件下载步骤:
代码实现:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.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>