Idea创建项目

创建Java项目

  1. file->new->Project

    image-20230327155937310

  2. 选中Java->选择本地安装的jdk->点击next

    image-20230327160155781

  3. 一直点击next直到下面图片中设置项目的名称和地址

    image-20230327160758158

  4. 项目结构

    image-20230327160957954

  5. 在项目基础上添加jar包依赖->找到对应的jar地址添加进来->当在External Libraries中存在对应的jar包名称表示添加依赖成功。

    image-20230327162029677

创建javaWeb项目(本地Jar包方式)

按照上操作创建好一个java普通项目

修改普通java项目为JavaWeb项目

  1. 添加项目模块支持->选择web application(4.0),记住勾选create web.xml

    image-20230327174556699

  2. 完成之后,可以看到项目下新建了web目录,并包含了web.xml和index.jsp文件。

  3. 在WEB-INF下新建文件夹classes(存放编译后的class文件)和lib(存放开发需要的jar包)

  4. 打开项目结构(Project Structure)

    • 进行项目配置

    image-20230328144355075

    • 模块配置(注意这里的输出路径可以设置为上面创建的classes文件夹也可以使用默认的地址,只是后续上线的话,要去对应的classes文件夹中获取class文件去部署)

    image-20230328144707580

    • Facets配置:这里指定了web目录不是一个普通的文件夹,而是web项目,如下配置,相同则无需修改

      image-20230328145520480

    • 配置Artifacts(这里将项目打包成war包)

      image-20230328145749584

  5. 添加tomcat

    image-20230328150325975

    配置Deployment,这个操作可以让Tomcat找到war包所在的位置,从而将web项目部署在Tomcat服务器上并修改下面中的application contex为/(这样项目默认访问路径为localhost:8080/index.jsp)

    image-20230328150532889

  6. 添加项目所需的依赖

    file->project structure->Modules->dependencies->JARs Or Directories->选中创建的lib文件夹->Jar Directory->ok

    image-20230328161438216

image-20230328161700904

  • file->project structure->Modules->dependencies->library->选择Tomcat

image-20230328161855376

记住要勾选上述添加的依赖

image-20230328162000948

最后,可以看到导入进来了

image-20230328162033944

  1. 最后启动项目

Maven项目整合SSM

分别讲解了Mybatis、SpringMVC,Spring,最后又将三者整合成SSM框架

参考文档

Maven创建JavaWeb项目

创建项目

使用Maven骨架创建,选择webapp,如图所示

image-20230406140517915

配置项目使用Maven的配置信息

image-20230406140735948

创建完成后的目录结构如下图

image-20230406141051743

由此可见没有java文件夹和resources文件夹,需要自己手动新建并设置文件夹的属性

image-20230406141543778

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- 数据库jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- jsp标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--单元测试的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

配置Tomcat

查看上面javaweb的配置Tomcat的方式

启动EL表达式配置

使用骨架创建的web项目是不能用EL表达式的

原因:idea给我们提供的代码模板默认使用的2.3版本,可以修改版本,也可以在jsp中添加代码。解决方案选择其一,推荐第二种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.在jsp页面中增加
<%@ page isELIgnored="false"%>

2.修改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_3_1.xsd" version="3.1">
</web-app>

配置lombok插件

常用注解

  • @Setter/@Getter

    注解在属性上,为属性提供setter/getter方法

  • @ToString

    为类生成toString方法,输出类名和所有属性

  • @EqualsAndHashCode

    生成equal和hashCode方法,可以通过参数,排除一些属性

  • @NoArgsConstructor

    注解在类上,为类提供一个无参的构造方法

  • @RequiredArgsConstructor

    会生成一个包含常量(final修饰)和标识了NotNull的变量的构造方法

  • @AllArgsConstructor

    注解在类上,为类提供一个全参的构造方法

  • @Data

    注解在类上相当于@Getter、@Setter、@ToString等几个注解的合集

  • @Log4j

    注解在类上,为类提供一个属性名为log的log4j日志对象

Mybatis

原生CRUD的问题

image-20230406145533639

  1. 编码过于繁琐
  2. 结果集映射成对象需要我们自己编写代码
  3. 性能一般
  4. sql语句与java代码高度耦合

ORM

Object-Relationl Mapping,对象关系映射,它的作用是在关系型数据库和对象之间做一个映射,这样我们在具体的操作数据库的时候,只要像平时操作对象一样操作它就可以了,ORM框架会根据映射完成对数据库的操作,就不需要再去和复杂的SQL语句打交道

Hibernate

  • 是全自动ORM框架
  • 自动进行对象和结果集的转换;sql自动生成和执行hql
  • 重量级;更新慢

Mybatis

  • 是半自动ORM框架
  • 开发人员手动写sql
  • 轻量级;更新快;灵活性好

添加依赖

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>

配置文件

核心配置文件

在resources目录下新建:sqlMapConfig.xml,内容可以在官网查看,或下面代码 官网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc_driver}"/>
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_username}"/>
<property name="password" value="${jdbc_password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/> 一会此处需要修改
</mappers>
</configuration>

一会需要添加两个标签:
1.properties 配置文件,存放配置参数
2.typeAliases 自动扫描beans包,自动将类起别名,别名是:类名首字母小写
properties标签

可以直接在value中配置,也可以单独放到一个properties文件中,若希望将配置数据放到jdbc.properties,在xml添加

1
<properties resource="jdbc.properties"></properties>

image-20230407094024280

1
2
3
4
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/demo?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=root
typeAliases标签

大概的意思是:如果不加typeAliases,那么在映射文件中需要将实体类的地址写全,也就是com.zhuixun.domain.UserInfo,加上之后,只需要写userInfo就知道对应的实体是哪一个

1
2
3
4
<!--写上之后mybatis自动扫描domain包,自动将类起别名,格式为类名首字母小写-->
<typeAliases>
<package name="com.zhuixun.domain"></package>
</typeAliases>

映射文件配置

新建bean对应的xml

在resource下新建相同的包名,创建一个与user_info表对应的xml映射文件

注意:

  1. 路径必须和domain一致
  2. 在resource中创建时一级一级新建文件夹,不能直接使用com.zhuixun.mapper,因为resource下会叫”.”作为文件名的一部分

image-20230407100226269

补充UserInfoMapper.xml内容,可以从官网摘抄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>

注意映射文件的命名空间:
<mapper namespace="org.mybatis.example.BlogMapper">
在传统模式开发下,命名空间写什么都可以,没有用,如果觉得爆红不好看可以写成domain的目录,idea就不会爆红了(但注意,实际没有其他用处)
<mapper namespace="com.zhuixun.domain.UserInfo">
具体应该写什么在 基于接口代理模式开发中说明

改成现在需要内容为:

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhuixun.domain.UserInfo">
</mapper>
修改核心文件配置

需要在SqlMapperConfig.xml中新增如下信息,对应刚刚新建的xml:

1
2
3
<mappers>
<mapper resource="com/zhuixun/mapper/UserInfoMapper.xml"/>
</mappers>

初试sql

映射文件

在映射文件中编写查询的sql

1
2
3
<select id="findUserInfoAll" resultType="com.zhuixun.domain.UserInfo">
select * from user_info
</select>

由于我们之前配置了typeAliases标签,可以这样写,resultType代表返回类型

1
2
3
<select id="findUserInfoAll" resultType="userInfo">
select * from user_info
</select>

新建UserInfo实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.zhuixun.domain;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;

/**
* @Title: UserInfo
* @Author huan
* @Package com.zhuixun.domain
* @Date 2023/4/7 9:57
* @description: 用户信息类
*/
@Data
public class UserInfo {
//主键
private Long userId;
//用户名
private String userName;
//年龄
private Integer userAge;
//性别
private String userSex;
//密码
private String userPass;
//用户标识 1:生效 2:删除
private String userStatus;
//创建时间
private LocalDateTime createTime;
//更新时间
private LocalDateTime updateTime;
}

Dao层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void findAllUserInfo()throws Exception{
//1.获取主配置文件
InputStream inputStream = Resources.getResourceAsStream("sqlMapperConfig.xml");

//2.由建造者模式创建一个工厂类
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.由工厂类创建一个产品
SqlSession sqlSession = sqlSessionFactory.openSession();

//4.sqlSession中有很多方法
/* 这里怎么知道findUserInfoAll
1. 加载了主配置文件
2. 主配置文件的mappers标签中写明了映射文件的地址
*/
List<UserInfo> userInfoList = sqlSession.selectList("findUserInfoAll");
for (UserInfo userInfo : userInfoList) {
System.out.println(userInfo);
}
}

数据映射问题

目前为止,是可以查出数据,但是运行代码,会发现查出来的数据全是null

原因:虽然从数据库查询到了数据,但是数据的列名是这样的

1
user_id user_name user_sex user_pass

而我们定义resultType中返回的User实体类的属性是这样的

1
userId userName userSex userPass

Mybatis并不能自动的将user_id映射成userId

解决思路:

主要是让Mybatis知道user_id到底是哪一个数据,它该放到哪里,需要制定映射方案

  • 解决1:为列取一个别名,让查出来的user_id改名为userId

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        <select id="getUserInfo" resultType="userInfo">
    select
    user_id userId,user_name userName,user_age userAge, user_sex userSex, user_pass userPass
    from user_info
    </select>

    备注:通过使用 SQL,可以为表名称或列名称指定别名。
    SELECT column_name AS alias_name FROM table_name;
    as可省略

  • 写一个resultMap标签,设置id和type属性,在内部编写映射方案

    • id元素:用于设置主键字段与实体类属性的映射关系
    • result元素:用于设置普通字段与实体类属性的映射关系
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <resultMap id="resultMap" type="com.zhuixun.domain.UserInfo">
    <id column="user_id" property="userId" javaType="java.lang.Long" jdbcType="BIGINT"></id>
    <result column="user_name" property="userName" javaType="java.lang.String" jdbcType="VARCHAR"></result>
    <result column="user_age" property="userAge" javaType="java.lang.Integer" jdbcType="INTEGER"></result>
    <result column="user_sex" property="userSex" javaType="java.lang.String" jdbcType="CHAR"></result>
    <result column="user_pass" property="userPass" javaType="java.lang.String" jdbcType="VARCHAR"></result>
    <result column="user_status" property="userStatus" javaType="java.lang.String" jdbcType="CHAR"></result>
    <result column="create_time" property="createTime" javaType="java.time.LocalDateTime" jdbcType="DATETIMEOFFSET"></result>
    <result column="update_time" property="updateTime" javaType="java.time.LocalDateTime" jdbcType="DATETIMEOFFSET"></result>
    </resultMap>

    <select id="findUserInfoAll" resultMap="resultMap">
    select * from user_info
    </select>
  • mybatis自定义的SQL语句中,如select语句,如果数据库表的字段为驼峰命名,即如user_name这样的形式,那么select语句执行的结果会变成null。

    • 在mybatis文件中开始驼峰命名(推荐)

      1
      2
      3
      4
      5
      6
      7
      8
      <configuration>
      <!-- 开启驼峰映射 ,为自定义的SQL语句服务-->
      <!--设置启用数据库字段下划线映射到java对象的驼峰式命名属性,默认为false-->
      <settings>
      <setting name="mapUnderscoreToCamelCase" value="true"/>
      </settings>
      </configuration>

日志管理Log4j

在开发过程中我们很多时候需要对sql进行调试,查看参数或者查看最后的sql什么样子,之前我们可以使用debug或者使用在控制台打印的方式查看,但是现在我们放到了xml中??怎么跟进sql??

需要借助日志工具Log4j2

添加依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>

添加log4j2.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>

<RollingFile name="RollingFile" filename="log/qst.log"
filepattern="${logPath}/%d{YYYYMMddHHmmss}-fargo.log">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>

</Appenders>

<!-- DEBUG级别 Console控制台 RollingFile文件 -->
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile" />
</Root>
</Loggers>
</Configuration>

基于接口代理模式开发

  1. Mybatis要求使用mapper作为接口文件夹名称(保证了编译后在同一文件夹),且接口名需要和映射文件同名
  2. mapper文件夹下放接口,接口方法名和映射文件中的id名相同
  3. 映射文件的命名空间namespace,在基于接口代理开发时,需要指定mapper文件夹下的接口文件

image-20230407154855639

修改代码

image-20230407155149383

  1. 新增mapper文件夹以及UserInfoMapper接口类

  2. 映射文件修改namespace

    1
    2
    <mapper namespace="com.zhuixun.mapper.UserInfoMapper">
    </mapper>
  3. UserInfoMapper接口定义方法与映射文件的id名一致

    1
    2
    3
    4
    5
    /**
    * 获取所有的用户信息
    * @return
    */
    List<UserInfo> findUserInfoAll();
    1
    2
    3
    <select id="findUserInfoAll" resultType="com.zhuixun.domain.UserInfo">
    select * from user_info
    </select>
  4. 在service层修改代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class UserInfoService {
    public List<UserInfo> getUserInfoAll() throws Exception{
    //1.获取主配置文件
    InputStream inputStream = Resources.getResourceAsStream("sqlMapperConfig.xml");

    //2.由建造者模式创建一个工厂类
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //3.由工厂类创建一个产品
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //4.sqlSession中有很多方法
    UserInfoMapper userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);
    List<UserInfo> userInfoAll = userInfoMapper.findUserInfoAll();
    userInfoAll.forEach(userInfo->System.out.println(userInfo));
    return userInfoAll;
    }
    }

SpringMvc

分析理解MVC

mybatis 替换的是DAO连接数据库

SpringMvc替换的是前端和servlet这部分

image-20230407160905292

工作流程

image-20230407161036408

HandlerMapping处理器映射器

  • DispatcherServlet:不处理任何请求,但是接收全部请求
  • HandlerMapping:处理请求,处理器Handler和URL的映射关系
  • 这样DispatcherServlet就知道往哪里转发请求,即给哪个Handle

image-20230407162247917

HandlerAdapter处理器适配器

调用Handler(或说servlet)中间有个适配器是为了解耦,Handler是我们编写的业务代码(Controller)

ViewReslover视图解析器

返回视图时做一个解析操作,再返回真正的视图字符串之前找到视图字符串在哪里

SpringMVC引入

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>

配置前端控制器

dispatcherServlet就是一个servlet,dispatcherServlet需要接收全部请求

注意:/拦截所有的非jsp,/*拦截所有请求

在web.xml中配置servlet

1
2
3
4
5
6
7
8
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

创建springmvc.config配置文件

image-20230407164902393

配置文件中是对Springmvc各个组件配置的,现在我们没有配置,但需要在web.xml去加载这个文件

正常情况下,DispatcherServlet在初始化的时候我们可以通过给其contextConfigLocation传递参数进行设置,配置文件所在路径

1
2
3
4
5
6
7
8
9
10
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--默认寻找同级目录下,也就是/WEB-INF/dispatcherServlet-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvcConfig.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

SpringMvc初步配置

基础配置:配置三大组件和我们业务控制器

创建Controller

实际上controller不会这样使用,这里只是做一个测试(如果这样一个handler写一个类,不和servlet一样了吗)

1
2
3
4
5
6
7
8
9
public class TestController implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
return modelAndView;
}
}

配置三大组件以及添加业务控制器

1
2
3
4
5
6
7
8
9
10
<beans>
<!--配置Handler处理器,用于相应的/testController请求-->
<bean name="/testController" class="com.zhuixun.controller.TestController"></bean>
<!--配置映射器,将handler处理器的name作为url进行查询-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!--配置适配器,用于对Controller中的handleRequest()方法的调用-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>

完善视图解析器

正常开发jsp我们一般会放到安全目录下,因此我们在WEB-INF下新建一个jsp目录存放我们的jsp页面

image-20230407174159802

然后通过controller层返回视图

1
2
3
4
5
6
7
8
9
public class TestController implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/jsp/login.jsp");
return modelAndView;
}
}

现在我们设置jsp的路径还是挺长(”/WEB-INF/jsp/login.jsp”),这个时候我们可以使用视图解析器的配置对返回值进行优化,修改配置文件中的视图解析器,增加两个属性

1
2
3
4
5
<!--配置视图解析器 和属性-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

这样在访问的路径上自动添加前缀和后缀

1
2
3
4
5
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login");
return modelAndView;
}

基于SpringMVC注解改造项目

上面的基础的改造我们发现实际上并没有比Servlet简化多少

org.springframework.stereotype.Controller注解类型用于将类的实例指定为控制器,使用@Controller注解标注的类无需继承特定的类或者实现特定的接口

  1. 在Springmvc配置文件中引入spring-context
  2. 使用<context:component-scan/ >元素配置包的扫描范围
  3. 在对应的类中使用@Controller对类进行注解

image-20230410104907829

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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">
<!--配置Handler处理器,用于相应的/testController请求-->
<!--<bean name="/testController" class="com.zhuixun.controller.TestController"></bean>-->

<!--这里统一通过扫描包的方式去扫描指定包下的@Controller注解替换一个个添加handler和url的方式-->
<context:component-scan base-package="com.zhuixun.controller" />
<!--增加注解驱动依赖-->
<mvc:annotation-driven></mvc:annotation-driven>

<!--配置映射器,将handler处理器的name作为url进行查询-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!--配置适配器,用于对Controller中的handleRequest()方法的调用-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!--配置视图解析器 和属性-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
1
2
3
4
5
6
7
@Controller
public class UserInfoController {
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
}

静态资源问题

我们前端的常见资源有js、css、img等等,这些都是会被dispatcherServlet拦截到,所以我们需要对静态资源放行

image-20230410112251021

1
2
3
4
5
<!--    mapping代表访问的URL **代表任意层级,location是webapp下面的文件地址  -->
<!-- <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>-->
<!-- <mvc:resources mapping="/img/**" location="/img/"></mvc:resources>-->
<!-- <mvc:resources mapping="/css/**" location="/css/"></mvc:resources>-->
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>

参数注入

乱码问题

  1. get请求方式乱码可以修改Tomcat的server.xml,如果没有则不需要修改

  2. post请求中文乱码,需要在web.xml中添加过滤器转码

    注意:下面这个过滤器一定要写到所有过滤器之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--springMVC提供的编码过滤器-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

时间Date

  1. 单独时间

    @DateTimeFormat(pattern = “yyyy-MM-dd”)

    1
    2
    3
    4
    5
    @RequestMapping("time")
    public String time(@DateTimeFormat(pattern = "yyyy-MM-dd") Date userTime) {
    System.out.println(userTime);
    return "restful";
    }
  2. 实体类中有时间属性

    在实体类中添加注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    entity:
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date userTime;

    controller中正常:
    @RequestMapping("timeClass")
    public String timeClass(UserInfo userInfo) {
    System.out.println(userInfo.toString());
    return "restful";
    }

响应返回

转发和重定向

  1. 转发到其他Controller

    1
    return "forward:restful";
  2. 重定向

    1
    return "redirect:/resuful";

响应Json

**@ResponseBody**:可以直接将返回的字符串数据作为响应内容,即设置controller返回的是一个Json数据,而不是视图

如果整个Controller类的方法都是返回Json
@RestController的作用等同于@Controller + @ResponseBody

数据校验

  1. 添加依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.0.Final</version>
    </dependency>
  2. 实体类添加约束

    1
    2
    3
    //主键
    @NotNull(message = "主键id不能为空")
    private Long userId;
  3. 在方法属性设置此类需要被检查@Valid,且设置了接受错误信息的BindingResult

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @RequestMapping("register")
    public String register(@Valid UserInfo userInfo, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
    List<FieldError> errors = bindingResult.getFieldErrors();
    for (FieldError error : errors) {
    System.out.println(error.getDefaultMessage());
    }
    }
    System.out.println("-----------");
    System.out.println(userInfo.toString());
    return "login";
    }

文件上传

SpringMVC为文件上传提供了直接支持,即MultipartResolver接口,具有即插即用特征。SpringMVC提供了CommonsMultipartResolver类,该类通过Commons FileUpload技术实现了MultipartResolver接口。因此使用SpringMVC上传功能时需要提供Commons FileUpload依赖支持。

  1. 引入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--        文件上传       -->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
    </dependency>

  2. 在Springmvc配置文件中添加配置

    1
    2
    3
    4
    5
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <property name="maxUploadSize" value="1024000"></property>
    </bean>

  3. jsp设置表单的提交enctype

    1
    2
    3
    <form action="" method="post" enctype="multipart/form-data">

    </form>
  4. controller层接收

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @RequestMapping("register")
    public String register(MultipartFile userImg) throws IOException {
    System.out.println(userImg.getOriginalFilename());
    String fileUrl = "D:\\" + userImg.getOriginalFilename();
    File file = new File(fileUrl);
    //正常我们文件会选择放到本项目路径下或者选择一个文件服务器作为存储
    userImg.transferTo(file);

    return "login";
    }

文件下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping("/downloadFile")
public ResponseEntity<byte[]> download(HttpServletRequest request) throws Exception {
//获取要下载文件的路径及输入流对象
ServletContext servletContext = request.getServletContext();
String realPath = servletContext.getRealPath("/static/img/logo.jpg");
FileInputStream fileInputStream = new FileInputStream(realPath);
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
fileInputStream.close();
//将要下载文件内容返回
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Content-Disposition","attachment;filename=logo.jpg");
return new ResponseEntity<byte[]>(bytes,httpHeaders, HttpStatus.OK);
}

拦截器

SpringMVC中提供了Interceptor拦截器,用于拦截用户的请求并进行相应的处理,如权限认证、判断用户是否登录等。

SpringMVC拦截器是一种可插拔式的设计,当需要使用某个拦截器时,只需要在配置文件中应用该拦截器即可;当不需要该拦截器时,取消配置文件中的配置。

SpringMVC中的拦截器是通过实现HandlerInterceptor接口或继承HandlerInterceptorAdapter抽象类来完成的。

重写三个方法

  1. preHandle

    这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false

    当preHandle()方法返回true时,继续向下执行处理器中的方法,否则不再向下执行

  2. postHandle

    当preHandle()方法返回true时,且在Controller方法被调用之后被调用;

    postHandle()方法在DispatcherServlet进行视图返回渲染之前被调用,因此在方法中可以对Controller处理之后的ModelAndView对象进行操作

  3. afterCompletion

    这个方法在DispatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TestInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("一:1111111111");
return HandlerInterceptor.super.preHandle(request, response, handler); // true
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("一:2222222222");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("一:3333333333");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}

springmvc配置:

1
2
3
4
5
6
7
8
springMVC配置:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<bean class="com.zhuixun.interceptor.TestInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

如果配置多个拦截器,拦截器的执行顺序是根据配置顺序来的

Spring

主要是通过Spring的IOC去控制对象的创建管理,和AOP做统一处理

SSM整合

spring主要帮我们解决的是依赖关系Controller-service-dao(现在Dao层不用,而mapper接口也不用我们new,它是代理类帮我们创建的,所以目前IOC帮我们的是Controller-Service层)

分析

  1. 现在我们在Service中用的是手写的Mybatis工具类,工具类的流程是:SqlSessionFactoryBuilder–>SqlSessionFactory–>SqlSession–>getMapper

  2. 原先我们使用Mybatis就是在service层中使用sqlsessionfactory和sqlsession获取mapper代理类

  3. 既然我们要解决依赖关系;需要解决Service调用代理类的依赖所以我们可以思考出来我们需要把sqlsessionfactory和sqlsession获取mapper代理类的创建都交给Spring

  4. mapper代理类可以由SqlSession创建,所以最终我们只需要让Spring管理我们sqlsessionfactory和sqlsession对象即可

我们的最终目的是IOC可以帮我们管理Controller、Service、mapper

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>

新建application.xml

创建一个配置文件(名字不太重要),进行Spring配置文件配置

数据库信息

我们需要让IOC创建sqlsessionfactory和sqlsession;必然要连接数据库,所以数据库信息需要配置到IOC中,数据库信息在jdbc.properties中,使用<context:property-placeholder >引入属性文件,将数据库连接信息放到一个对象中,方便注入

1
2
3
4
5
6
7
8
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>

创建sqlsessionfactory

这里不需要直接创建mybatis核心包中的类SqlsessionFactory,我们引入mybatis整合spring包,使用其中的SqlSessionFactoryBean更加合适,同时配置需要注入必须得数据源,以及常用的别名扫描配置

1
2
3
4
<bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.zhuixun.domain"></property>
</bean>

创建sqlsession

我们这里也不需要单独配置管理sqlsession,而选择用整合包给我提供的一个映射文件扫描类MapperScanerConfigurer

一个映射文件扫描器,主要的作用就是扫描映射文件,生成mapper代理类,因此我们至少需要配置两个属性

  1. 要扫描那些映射文件
  2. 扫描出来的映射文件使用哪个sqlsessionFactory去处理生成代理类
1
2
3
4
5
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zhuixun.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
</bean>

添加扫描Service层的配置

1
<context:component-scan base-package="com.zhuixun.services"></context:component-scan>

Controller层已经在springmvc-config.xml中扫描过了,不需要再扫描,如果再写一个,SpringIOC会生成两个Controller对象。(SpringMVC在创建时就有一个SpringIOC容器)

Spring容器配置

在web.xml中增加项目启动创建spring容器配置,这里要使用到监听器监听应用域启动创建IOC容器

ContextLoaderListener是Spring框架帮我们提供很好的监听器直接配置使用即可

1
2
3
4
5
6
7
8
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

全部配置文件

Spring配置applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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:aop="http://www.springframework.org/schema/aop"
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">

<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.zhuixun.domain"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zhuixun.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
</bean>
<context:component-scan base-package="com.zhuixun.services"></context:component-scan>
<!-- 扫描AOP的包 -->
<context:component-scan base-package="com.zhuixun.interceptor"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

jdbc.properties

1
2
3
4
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/guangxissmdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=root

SpringMvc配置(Springmvc-config.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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">

<!-- 配置包扫描范围,先找到所有的controller -->
<context:component-scan base-package="com.zhuixun.controller"></context:component-scan>
<!-- 增加注解依赖驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

<!-- mapping代表访问的URL **代表任意层级,location是webapp下面的文件地址 -->
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
<!-- 拦截器地址 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/toLogin"/>
<bean class="com.zhuixun.interceptor.TestInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>


</beans>

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!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_3_1.xsd" version="3.1">
<!-- Spring容器:监听器监听应用域启动创建IOC容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--springMVC提供的编码过滤器-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- dispatcherServlet -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 默认寻找同级目录下 也就是/WEB-INF/dispatcherServlet-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>

<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- HTTP中RESTFULE支持(put、delete请求):添加一个拦截器,拦截请求根据参数进行转化 -->
<filter>
<filter-name>hidden</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hidden</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

</web-app>

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

<!-- servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- 数据库jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- jsp标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>


<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>

<!-- log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>

<!-- Json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>

<!-- 数据校验 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>

<!-- 文件上传 -->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

<!--单元测试的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>

Idea创建项目
http://example.com/2024/09/01/创建项目/Idea创建项目/
作者
zhuixun
发布于
2024年9月1日
许可协议