java菜鸟的SSM项目(CRUD)梳理

因为工作原因,需要写SSM项目,但是好久没弄这块了,都忘得差不多了,看着密密麻麻的代码很是绝望。还好自己之前有写过SSM项目,打算通过把自己的简单项目重新梳理一遍,来达到恢复记忆的目的,正好也在这里和大家分享一下。
之前整理的文章在我的博客里里有,链接如下:https://blog.csdn.net/NewBeeMu/article/details/100834780
话不多说,开始干活
友情提示,底下为了更好的理清逻辑,有把之前的东西推动重来,不想看的可以跳过前半部分,直接看后面。
java菜鸟,刚刚入行,如果有哪里不对,欢迎指正,谢谢!
---------------------------------------------------------------分割线---------------------------------------------------------------------
首先,新建一个maven项目,刚建出来的时候莫名其妙连个src都没有,没关系,自己建就好了。
然后写pom.xml,给点时间给他下载。
果然一出手就全是问题,依赖下不下来,提示我找不到,如图:
在这里插入图片描述
这种情况是之前下的依赖有问题,但是它占着位置,正确的依赖下不了。解决方法也很简单,把本地maven仓库里面所有org都删了重新下就完事了。
在这里插入图片描述
还有一个小插曲,我写的版本号错了一个字母,应该是RELEASE,我写成了RElEASE,还好发现了,不然估计也要折腾半天。
依赖搞定了,可以开始写代码了。
写代码前,先把框架搭起来。因为不是第一次写,所以我直接对照着我的博客把文件夹都建好了
在这里插入图片描述
然后先把配置文件弄好
在这里插入图片描述
这个时候非常感谢我的师傅,给我大概的讲了一下整个的逻辑吧。
以下是我根据他给我讲的时候的录音整理出来的。
首先,在test.java里面写了一点代码

package text.ssm;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {

    @Test
    public void test(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("springMVC.xml");
        applicationContext.getBean("");
    }
}

因为我用的是xml配置,而不是注释配置,所以一般用的是ClassPathXmlApplicationContext。按下Ctrl进入ClassPathXmlApplicationContext,是这行代码
在这里插入图片描述
这个其实就是就是初始化了一个ClassPathXmlApplicationContext。按下Ctrl进入this,可以看到
在这里插入图片描述
就相当于refresh,也就是相当于刷新了他的容器。
接下来,好吧,我承认我听着录音还是晕了。放弃深究源码了,还是先尝试跑起来再说吧。

<?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"
       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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

    <bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

    <!--  <bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
          <property name="sqlSessionFactory" ref="SqlSessioinFactory"></property>
          <property name="mapperInterface" value="text.ssm.mapper.DepartmentMapper"></property>
      </bean>

      <bean id="service" class="text.ssm.service.impl.DepartmentServiceImpl">
          <property name="mapper" ref="departmentMapper"/>
      </bean>-->

    <!--配置mapper接口扫描
        从配置的包中,扫描所有的接口,并且创建接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="text.ssm.mapper"/>
        <!--容器中有多个sqlSessionFactory的时候才需要配置,只有一个sqlSessionFactory的时候可以不配置-->
        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />-->
    </bean>

    <!--IoC注解扫描-->
    <context:component-scan base-package="text.ssm"/>


    <!--事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!--配置事务-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution( * text.ssm.service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="list*" read-only="true"/>
            <tx:method name="select*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>


</beans>

这是application.xml,头文件就不深究了,忒难了,往下看吧。

<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

1.有些参数在某些阶段中是常量
比如 :
a、在开发阶段我们连接数据库时的连接url,username,password,driverClass等
b、分布式应用中client端访问server端所用的server地址,port,service等
c、配置文件的位置
2.而这些参数在不同阶段之间又往往需要改变
比如:在项目开发阶段和交付阶段数据库的连接信息往往是不同的,分布式应用也是同样的情况。

期望:能不能有一种解决方案可以方便我们在一个阶段内不需要频繁书写一个参数的值,而在不同阶段间又可以方便的切换参数配置信息
解决:spring3中提供了一种简便的方式就是context:property-placeholder/元素

<context:property-placeholder 
	location="属性文件,多个之间逗号分隔"  
    file-encoding="文件编码"  
	ignore-resource-not-found="是否忽略找不到的属性文件"  
	ignore-unresolvable="是否忽略解析不到的属性,如果不忽略,找不到将抛出异常"  
	properties-ref="本地Properties配置"  
	local-override="是否本地覆盖模式,即如果true,那么properties-ref的属性将覆盖location加载的属性,否则相反"  
	system-properties-mode="系统属性模式,默认ENVIRONMENT(表示先找ENVIRONMENT,再找properties-ref/location的),NEVER:表示永远不用ENVIRONMENT的,OVERRIDE类似于ENVIRONMENT"  
	order="顺序"  
        />

也就是调用db.properties吧

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=123456

配置连接池

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

---------------------------------------------------------------分割线---------------------------------------------------------------------
为了理清逻辑,我又把之前建的文件夹都删了。依赖也删了,用一个下一个。然后在ssm文件夹下建了三个文件夹,bean,mapper和service。
首先,在bean下面新建Department.java

public class Department{
	private Integer id;
	private String name;
	private String location;
}

这个时候我们想要对对象进行一个封装,所以需要加注解,但是我们发现没有包
在这里插入图片描述
所以我们需要导一个包。
这里就省略了,大家应该都知道。

<!--lombok-->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.16.20</version>
</dependency>

这个时候就可以去添加注解了,Setter,Getter和ToString,两个构造函数NoArgsConstructor和AllArgsConstructor

@Setter@Getter@ToString
@NoArgsConstructor@AllArgsConstructor
public class Department{
	private Integer id;
	private String name;
	private String location;
}

接下来要去准备对象对应的一张表,所以我们打开数据库进行创建
在这里插入图片描述
接下来,我们要去写对应的mapper接口,就属于是Dao层
首先我们创建一个接口,通常的命名规范是:对象+Mapper,比如这次我们建的就是DepartmentMapper

public interface DepartmentMapper {
	Integer save(Department d);
	Integer update(Department d);
	Integer delete(Integer id);
	Department get(Integer id);
	List<Department> list();	
}

上面五个分别对应增加,更改,删除,查找一个,查找多个
每一个接口要对应一个自己的映射文件
这个时候需要一个插件,所以继续在pom.xml中写

<build>
	<!--加载资源文件-->
	<resources>
		<resource>
			<directory>src/main/java</directory>
			<includes>
				<include>**/*.xml</include>
				<include>**/*.properties</include>
			</includes>	
		</resource>
		
		<resource>
			<directory>src/main/resources</directory>
			<includes>
				<include>**/*.xml</include>
				<include>**/*.properties</include>
			</includes>	
		</resource>
	</resources>
<build>

这个时候就可以在mapper文件夹下新建一个映射文件DepartmentMapper.xml
这时候头文件可能会红,比如这样
在这里插入图片描述
这个时候把右下角的检查的级别从最高改成中级就好了。
如果还不行,Alt+回车,应该是要下载个东西
在这里插入图片描述
然后就绿了
这个时候注意,从上图可以看到,namespace后面是空的,写的时候要把接口的全限定名复制到namespace
这个时候开始写sql语句
id和接口中的方法名保持一致
这里注意,useGeneratedKeys这个只在insert语句中有效,正常情况下useGeneratedKeys默认为false
当useGeneratedKeys为true时,如果插入的表id以自增列为主键时,将会把该自增id返回。
keyProperty=”对应的主键的对象

<!--id随便取,我们就取名叫做departmentMap吧,Type就是你要封装成什么对象,所以这里要用Department.java的全限定名,我就简写成Department.java了,知道就行-->
<resultMap id="departmentMap" Type="Department.java">
	<!--column表示的是数据库表中的字段名称,property表示的是实体类中定义的字段的名称-->
	<id column="id" property="id"></id>
	<result column="name" property="name"></result>
	<result column="location" property="location"></result>
</resultMap>

<insert id="save" useGeneratedKeys="true" KeyProperty="id">
	insert into department(name,location) values(#{name},#{location})
</insert>
<update id="update">
	update department set name = #{name},location = #{location} where id = #{id}
</update>
<delete id="delete">
	delete from department where id = #{id}
</delete>
<!--MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,但是resultType跟resultMap不能同时存在。-->
<!--为了举例,我这里用resultMap-->
<!--上面的是查询一个,下面的是查询列表-->
<select id="get" resultMap="departmentMap">
	select id,name,location from department where id = #{id}	
</select>
<select id="list" resultMap="departmentMap">
	select id,name,location from department	
</select>

接下来,我们要去创建service的接口和service的实现类
首先创建接口IDepartmentService.java
把上面的接口复制下来

public interface IDepartmentService {
	Integer save(Department d);
	Integer update(Department d);
	Integer delete(Integer id);
	Department get(Integer id);
	List<Department> list();	
}

再建service的实现类DepartmentServiceImpl.java
首先去实现接口中的五个方法

public class DepartmentServiceImpl implements IDepartmentService {

	//定义一个全局变量	
	private DepartmentMapper mapper;

	public Integer save(Department d) {
		return mapper.save(d);
	}
	public Integer update(Department d) {
		return mapper.update(d);
	}
	public Integer delete(Integer id) {
		return mapper.delete(id);
	}
	public Depertment get(Integer id) {
		return mapper.get(id);
	}
	public List<Department> list() {
		return mapper.list();
	}
}

那么到现在,从java bean对象,到表,到我们的dao层,现在不应该叫dao层,其实指的就是我们的mapper接口和mapper映射文件,然后就是,service接口和service实现类,所有的东西我们都已经准备好了。
我们现在想要获取到DepartmentServiceImpl这样一个实现类然后调用里面增删改查的方法,我们应该怎么做呢?
我们先新建一个测试类App.java
我们想要写注解,但是发现没有,这里我们又要去导包了,应该是spring的行为一些包。
我们先对spring的版本进行一个统一的管理

<properties>
	<project.spring.version>5.0.2.RELEASE</project.spring.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${project.spring.version}</version>
	</dependency>
</dependencies>

我们从右边的依赖关系可以看到,spring-context的依赖关系下包含这四个
在这里插入图片描述
我们接着来看

<properties>
	<project.spring.version>5.0.2.RELEASE</project.spring.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${project.spring.version}</version>
	</dependency>
	<!--我们接着去导入spring测试-->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>${project.spring.version}</version>
	</dependency>
	<!--因为要去加事务-->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>
		<version>${project.spring.version}</version>
	</dependency>
	<!--事务管理器-->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>${project.spring.version}</version>
	</dependency>
</dependencies>

这时候我急急忙忙就去写注释了,发现还是写不了,环顾一周,原来少了单元测试

<!--单元测试-->
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
</dependency>

好了,忙活了一圈,终于可以写测试类了

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {
	
}

这个时候我们要在resources底下new一个spring的配置文件,Spring Config一下application.xml
刚建好就是这样的
在这里插入图片描述
比方说,我想要去注入一个

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;
}

接下来,我想要一个测试的方法

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;

	@Test
	public void test() throws Exception {
		
		//创建一个部门对象
		//id,name,location
		Department d = new Department(null,"开发部","北京朝阳区")
		
		service.save(d);
	}
}

想要运行他,肯定配置文件application.xml里面不能为空啊
所以要加入

<bean id="service" class="DepartmentServiceImpl的全限定名"></bean>

但是想要调用save方法,实际上是调用mapper中的save方法,而目前mapper是空的,所以肯定不行
在这里插入图片描述
首先在mapper上加一个Setter

public class DepartmentServiceImpl implements IDepartmentService {

	//定义一个全局变量	
	@Setter
	private DepartmentMapper mapper;

	public Integer save(Department d) {
		return mapper.save(d);
	}
	public Integer update(Department d) {
		return mapper.update(d);
	}
	public Integer delete(Integer id) {
		return mapper.delete(id);
	}
	public Depertment get(Integer id) {
		return mapper.get(id);
	}
	public List<Department> list() {
		return mapper.list();
	}
}

然后

<bean id="service" class="DepartmentServiceImpl的全限定名">
	<property name="mapper" ref="mapper对象"/>
</bean>

因为mapper没有实现类,所以没办法通过构造器的方式创造对象。
所以只能用FactoryBean的方式来获取到一个mapper的对象
按传统方式获取mapper对象的话,
我想要获取一个mapper的对象,就得先获取一个sqlSession的对象
而想要获取sqlSession,首先需要有一个工厂factory
在这里插入图片描述
现在的问题是如何在spring的配置文件中获取mybatis的对象,这里就涉及到了mybatis和spring的整合
这个时候就需要导入mybatis和spring的桥梁

<!--mybatis和spring的桥梁-->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.3.2</version>
</dependency>

接下来我们去获取一个mapper对象,使用的方式是使用实现FactoryBean接口方式
我们看,左边的mybatis-spring的包下,mapper文件夹下,有一个MapperFactoryBean
在这里插入图片描述
在这里插入图片描述
首先,这个类,继承了SqlSessionDaoSupport,实现了FactoryBean,也就是说这个类中肯定会有一个getObject方法
我们去找一下,Ctrl+F,找到了,就是他
在这里插入图片描述
那么这个东西创建的对象就是getObject方法返回的对象
他返回的是谁?返回的应该就是我们的mapper对象
下载源码,我们用的就是我划起来的
abstract是继承
底下的那个oneMapper,它除了有一个sqlSessionFactory,还有一个mapperInterface需要去赋值
在这里插入图片描述
在这里插入图片描述
回到application.xml

<bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
	<property name="mapperInterface" value="DepartmentMapper的全限定名"/>
</bean>

这个bean,其实创建的就是mapper对象

<bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="sqlSessionFactory" ref="SqlSessionFactory"/>
	<property name="mapperInterface" value="DepartmentMapper的全限定名"/>
</bean>
<bean id="service" class="DepartmentServiceImpl的全限定名">
	<property name="mapper" ref="departmentMapper"/>
</bean>

但是现在我们可以看到,SqlSessionFactory还在报红呢
在这里插入图片描述

我们回去看源码,这个MapperFactoryBean的父类里面有SqlSessionFactory
在这里插入图片描述
在这里插入图片描述
这种方法里。是调用了另外的一种方法给sqlSession给赋了个值
但是现在SqlSession报错,是为什么呢?缺少mybatis的包
那就去加呗,再加一个mysql的驱动

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.4.6</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.38</version>
</dependency>

这个时候再回去看就好了
在这里插入图片描述
在这里插入图片描述
因为SqlSessionFactory是接口,所以没办法直接配置他的对象
在这里插入图片描述
在mybatis和spring的整合包里面,有个SqlSessionFactoryBean
先来看一下这个类在这里插入图片描述
实现了FactoryBean,泛型是SqlSessionFactory
这个类中肯定有一个getObject方法,这个方法返回的肯定是SqlSessionFactory
我们用Ctrl+F来看一下
在这里插入图片描述
果然,返回的就是SqlSessionFactory
所以,我们在application.xml中这么写

<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"></bean>

这样就不再报错了

在这里插入图片描述
我们发现,以我们之前的方式,创建一个SqlSessionFactory,读取的是mybatis的主配置文件
在主配置文件中我们都做了哪些事情呢?
在这里插入图片描述
这是传统的配置文件中我们需要配置的东西
我们想要获取一个sqlSessionFactory的对象,需要去配置别名,数据源和关联映射文件
进入SqlSessionFactoryBean这个类
有很多属性
在这里插入图片描述
我们需要给里面的很多属性赋一个值,才能创建SqlSessionFactory
configLocation是配置文件的地址,他用一个Resource去约束,也就是说configLocation这地方可以直接配置一个配置文件的字符串或者他的一个位置。
第二个我们先跳过
mapperLocations这是我们mapper映射文件的地址,他可以去配置一个数组
还有dataSource,数据源。
所以

<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<!--数据源-->
	<property name="dataSource" def=""/>
</bean>

写到这一步发现需要一个德鲁伊连接池,所以去导包

<!--德鲁伊连接池-->
<dependency>
	<groupId>org.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.9</version>
</dependency>

然后去配置一个德鲁伊连接池

<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

	<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!--数据源-->
		<property name="dataSource" def=""/>
	</bean>

在这里插入图片描述
这时候发现少了一个db.properties
我们就去创建一个

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=123

这个是我的,每个人根据自己的情况进行更改
然后我们可以继续写配置文件

<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

	<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!--数据源-->
		<property name="dataSource" def="dataSource"/>
	</bean>

然后去配置别名,其实也可以不配,但是不配的话就必须写全限定名,那样就会很麻烦
下面去关联mapper映射文件,value可以用字符串来写,填DepartmentMapper.xml的全限定名,记住要用斜线分割。因为是寻找文件,所以加上一个classpath:的前缀
也可以改成通配符*,表示所有*Mapper.xml都会注册到mapperLocations中
还有最后一个,关联mybatis的主配置文件
这个时候我们就需要创建一个mybatis的主配置文件mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>


    <!--配置延迟加载-->
    <settings>
    	<!--打开延迟加载的全局开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--不要积极地去查询关联对象-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--覆盖延迟加载的触发方法-->
        <setting name="lazyLoadTriggerMethods" value=""/>
    </settings>
    
</configuration>

那我们为了想让mybatis的主配置文件生效应该怎么办呢?
我们在创建SqlSessionFactory的时候关联一下mybatis的主配置文件,而关联的属性就是我们之前说的,SqlSessionFactoryBean中的configLocation。它就是用来关联我们说的mybatis的主配置文件的。
所以随后我们加上关联mybatis的主配置文件

    <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

    <bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

所以最后就是这样的
这个时候主键都有了,我们来尝试运行一下,我们来执行测试类,没有报错,找到数据库,刷新一下,有乱码在这里插入图片描述
至少说明除了乱码,别的是没有问题了
乱码怎么解决呢?我在网上百度了一下
在这里插入图片描述
所以我们在后面加上
在这里插入图片描述
这时候我们把日志清空一下,想看一下sql语句
在这里插入图片描述
但是想看日志还需要三个导包

    <!--日志的依赖-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.25</version>
    </dependency>

然后在加上一个配置文件,名字必须要叫做log4j.properties
注意别的可以直接复制,第四行再用是需要修改一下的

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.text.ssm=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

然后把之前的那个乱码删了,再执行一次,我们看看日志
在这里插入图片描述
这个就可以很明确的看出,执行了什么sql语句,什么属性,受影响的行数
然后刷新一下数据库
在这里插入图片描述
这就是我们mybatis和spring的整合,里面比较难的部分应该就是如何去获取SqlSession和如何去获取Mapper
我们前面只是实现了增加的操作,我们再来个update的操作

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;

	@Test
	public void test() throws Exception {
		
		//创建一个部门对象
		//id,name,location
		Department d = new Department(null,"开发部","北京朝阳区")
		
		service.save(d);
	}
	
	@Test
	public void testUpdate() throws Exception {
		
		Department d = new Department(2,"开发部","北京海淀区")
		
		System.out.println(service.update(d));
	}
}

我们也想看能不能打印出来他受影响的行数
运行一下
在这里插入图片描述
效果很明显
数据库刷新一下
在这里插入图片描述
会发现已经改掉了
把其他的也测试一下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;

	@Test
	public void test() throws Exception {
		
		//创建一个部门对象
		//id,name,location
		Department d = new Department(null,"开发部","北京朝阳区")
		
		service.save(d);
	}
	
	@Test
	public void testUpdate() throws Exception {
		
		Department d = new Department(2,"开发部","北京海淀区")
		
		System.out.println(service.update(d));
	}
	
	@Test
	public void testGet() throws Exception {
		
		System.out.println(service.get(2));
		
	}
}

运行
在这里插入图片描述
说明查询没有问题
然后还有一个查询列表

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;

	@Test
	public void test() throws Exception {
		
		//创建一个部门对象
		//id,name,location
		Department d = new Department(null,"开发部","北京朝阳区")
		
		service.save(d);
	}
	
	@Test
	public void testUpdate() throws Exception {
		
		Department d = new Department(2,"开发部","北京海淀区")
		
		System.out.println(service.update(d));
	}
	
	@Test
	public void testGet() throws Exception {
		
		System.out.println(service.get(2));
		
	}

	@Test
	public void testList() throws Exception {
		
		System.out.println(service.list());
		
	}
}

但是数据只有一行,我就再加一个数据
在这里插入图片描述
再去运行查询列表
在这里插入图片描述
说明也没有问题
最后去删除

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class App {

	@Autowired
	private IDepartmentService service;

	@Test
	public void test() throws Exception {
		
		//创建一个部门对象
		//id,name,location
		Department d = new Department(null,"开发部","北京朝阳区")
		
		service.save(d);
	}
	
	@Test
	public void testUpdate() throws Exception {
		
		Department d = new Department(2,"开发部","北京海淀区")
		
		System.out.println(service.update(d));
	}
	
	@Test
	public void testGet() throws Exception {
		
		System.out.println(service.get(2));
		
	}

	@Test
	public void testList() throws Exception {
		
		System.out.println(service.list());
		
	}
	
	@Test
	public void testDelete() throws Exception {
		
		System.out.println(service.delete(2));
		
	}
}

运行一下
在这里插入图片描述
数据库里面我们再去刷新一下
在这里插入图片描述
2就没有了,只剩下3了
到此为止,后台的整合已经全部搞定了
都知道Ioc是有两种方式的,xml和注解。
使用注解有另外一种更加简单的方式
还是在mybatis-spring整合包下面,有三个类,刚刚我们用的是第二个,MapperFactoryBean。现在我们来看看第三个
在这里插入图片描述
从名字上看,叫做Mapper扫描。扫描什么呢?扫描包,可以把包下面所有的接口创建出来对象
在这里插入图片描述
打开这个类
底下很多属性,首先看basePackage,这很显然是要配置一个包。我们刚刚说过的,这个类的作用就是从我们配置的包下面去扫描所有接口配置接口的代理对象
下面有一个setBasePackage的方法
在这里插入图片描述
所以说,我们去找他们的配置方式
在这里插入图片描述
这边有个例子
我来看一下,bean,他直接就是class,没有id属性,说明我们并不需要获取这个类的对象,我们只需要在spring容器当中去有这个类的对象就可以了,他的类就是刚刚我们看到的类
在这里插入图片描述
这是一个包
我们回到appliaction.xml,配置一个接口扫描

 <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

    <bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

  <!--  <bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="SqlSessioinFactory"></property>
        <property name="mapperInterface" value="text.ssm.mapper.DepartmentMapper"></property>
    </bean>

    <bean id="service" class="text.ssm.service.impl.DepartmentServiceImpl">
        <property name="mapper" ref="departmentMapper"/>
    </bean>-->

    <!--配置mapper接口扫描
        从配置的包中,扫描所有的接口,并且创建接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="text.ssm.mapper"/>
        <!--容器中有多个sqlSessionFactory的时候才需要配置,只有一个sqlSessionFactory的时候可以不配置-->
        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />-->
    </bean>

上面我注释了两段,配置mapper接口扫描是替换第一段内容的
接下来要去替换第二部分的内容,首先,要把service的实现类交给spring管理
找到service的实现类DepartmentServiceImpl,在上面添加注解

@Service
public class DepartmentServiceImpl implements IDepartmentService {

	//定义一个全局变量	
	@Setter
	private DepartmentMapper mapper;

	public Integer save(Department d) {
		return mapper.save(d);
	}
	public Integer update(Department d) {
		return mapper.update(d);
	}
	public Integer delete(Integer id) {
		return mapper.delete(id);
	}
	public Depertment get(Integer id) {
		return mapper.get(id);
	}
	public List<Department> list() {
		return mapper.list();
	}
}

这是Ioc注解,所以要添加Ioc注解扫描器

 <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

    <bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

  <!--  <bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="SqlSessioinFactory"></property>
        <property name="mapperInterface" value="text.ssm.mapper.DepartmentMapper"></property>
    </bean>

    <bean id="service" class="text.ssm.service.impl.DepartmentServiceImpl">
        <property name="mapper" ref="departmentMapper"/>
    </bean>-->

    <!--配置mapper接口扫描
        从配置的包中,扫描所有的接口,并且创建接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="text.ssm.mapper"/>
        <!--容器中有多个sqlSessionFactory的时候才需要配置,只有一个sqlSessionFactory的时候可以不配置-->
        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />-->
    </bean>

	<!--IoC注解扫描-->
    <context:component-scan base-package="text.ssm"/>

Ioc注解扫描其实就是把Service实现类交给spring,还需要注入一个mapper
所以把Setter换成Autowired,表示要从容器当中找一个mapper的对象

@Service
public class DepartmentServiceImpl implements IDepartmentService {

	//定义一个全局变量	
	@Autowired
	private DepartmentMapper mapper;

	public Integer save(Department d) {
		return mapper.save(d);
	}
	public Integer update(Department d) {
		return mapper.update(d);
	}
	public Integer delete(Integer id) {
		return mapper.delete(id);
	}
	public Depertment get(Integer id) {
		return mapper.get(id);
	}
	public List<Department> list() {
		return mapper.list();
	}
}

然后再运行一下service.get(3)
在这里插入图片描述
说明是没有问题的,所以注解也就搞定了
然后我们来配置事务
这时候发现我们还需要导入一个织入的包

<!--织入-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>

配置事务,他本质就是aop

 <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

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

    <bean id="SqlSessioinFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="text.ssm.bean"/>
        <!--关联mapper映射文件-->
        <property name="mapperLocations" value="classpath:text/ssm/mapper/*Mapper.xml"/>
        <!--关联mybatis的主配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

  <!--  <bean id="departmentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="SqlSessioinFactory"></property>
        <property name="mapperInterface" value="text.ssm.mapper.DepartmentMapper"></property>
    </bean>

    <bean id="service" class="text.ssm.service.impl.DepartmentServiceImpl">
        <property name="mapper" ref="departmentMapper"/>
    </bean>-->

    <!--配置mapper接口扫描
        从配置的包中,扫描所有的接口,并且创建接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="text.ssm.mapper"/>
        <!--容器中有多个sqlSessionFactory的时候才需要配置,只有一个sqlSessionFactory的时候可以不配置-->
        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />-->
    </bean>

	<!--IoC注解扫描-->
    <context:component-scan base-package="text.ssm"/>

	<!--事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!--配置事务-->
    <aop:config>
    	<!--包含子包-->
        <aop:pointcut id="txPointcut" expression="execution( * text.ssm.service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="list*" read-only="true"/>
            <tx:method name="select*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

在这里插入图片描述
这个时候我发现,头文件里面没有tx,tx在报红,没办法,就只能自己写了
把上面的aop的复制下来,改成tx
在这里插入图片描述
把下面的context复制下来,改成tx
在这里插入图片描述
为了验证事务是否设置好了,我们来抛个异常
在这里插入图片描述
运行一下,果然报错了
在这里插入图片描述
但是刷新数据库,并没有变化,说明事务就添加成功了
接下来,我们就要使用springMVC了,而使用springMVC,首先要有前段控制器,所以说我们先要去配置一个前端控制器。
这就是一个新的前端控制器web.xml
在这里插入图片描述
想要使用前端控制器,先要导入spingMVC相关的依赖

 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

在resources下再创建一个spring的配置文件springMVC.xml
先不管他,我们先把前端控制器写好

<!--前端控制器-->
  <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:springMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

接下来,有了前端控制器以后,我在浏览器再来进行访问的时候,那么这些请求就会到达前端控制器,然后前端控制器再对我们的请求进行一个分发,分发到我们对应的controller中
这时候我们新建一个controller的包,然后在里面新建一个类,DepartmentController.java
首先,我们把他交给spring管理,添加@Controller注解。Controller注解是Ioc注解。
我们需要把spring.xml的内容拷贝到springMVC.xml中,但是直接拷贝肯定不太好。
但我们可以用一个import标签,import标签就相当于拷贝

<!--引入后台的Spring配置文件-->
<import resource="classpath:application.xml"/>

我先这么创建几个文件夹
在这里插入图片描述
然后在department下创建list.jsp
然后我们在DepartmentController下其实应该这么写代码
在这里插入图片描述
但是/WEB-INF/views/ 这个路径以后多个页面的时候可能用的多,所以把/WEB-INF/views/还有.jsp抽取成一个视图解析器
这时候就需要在我们前端的配置文件中配置一下

	<!--mvc注解驱动-->
    <mvc:annotation-driven/>
	
	<!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

prefix:前缀
suffix:后缀
所以改完以后就可以这样了
在这里插入图片描述
然后配置一个tomcat,部署一下当前项目
在这里插入图片描述
在这里插入图片描述
apply
OK
接下来,启动一下tomcat
在这里插入图片描述
这里必须要加.do,因为加了.do才能被前端控制器拦截到
这只是个示范,接下来我们要去把真正的部门的信息,加载到浏览器上来
首先,直接注入IDepartmentService
在这里插入图片描述
然后写list.jsp的过程中发现需要导入jstl包

	<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

然后写list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>部门列表</h1>
	<table>
    	<tr>
        	<th>部门编号</th>
        	<th>部门名称</th>
        	<th>部门地址</th>
    	</tr>

    	<c:forEach items="${list}" var="dept">
        	<tr>
            	<td>${dept.id}</td>
            	<td>${dept.name}</td>
            	<td>${dept.location}</td>
        	</tr>
    	</c:forEach>
    	
	</table>
</body>
</html>

在这里插入图片描述
运行tomcat
在这里插入图片描述
但是部门编号其实有点不太好,因为我们肯定希望他是按顺序来填的,而不是他真正的id值
所以我们修改一下list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>部门列表</h1>
	<table>
    	<tr>
        	<th>部门编号</th>
        	<th>部门名称</th>
        	<th>部门地址</th>
    	</tr>

    	<c:forEach items="${list}" var="dept" varStatus="index">
        	<tr>
            	<td>${index.count}</td>
            	<td>${dept.name}</td>
            	<td>${dept.location}</td>
        	</tr>
    	</c:forEach>
    	
	</table>
</body>
</html>

运行tomcat
在这里插入图片描述
那想要新增怎么办呢?
我们在controller里增加一个东西
在这里插入图片描述
可以直接跳转到edit.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<center>
<h1>部门编辑</h1>
<form>
    部门名称:<input type="text" name="name"/><br/>
    部门地址:<input type="text" name="location"/><br/>
    <input type="submit" value="保存"/>
</form>
</center>
</body>
</html>

在这里插入图片描述
效果图如图所示。
然后再优化一下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<center>
<h1>部门编辑</h1>
<form action="/saveOrUpdate.do" method="post">
    部门名称:<input type="text" name="name"/><br/>
    部门地址:<input type="text" name="location"/><br/>
    <input type="submit" value="保存"/>
</form>
</center>
</body>
</html>

controller也增加一个方法
在这里插入图片描述
为了防止乱码,在web.xml上加请求编码过滤器

	<!--请求编码过滤器-->
  <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>

保存就可以做了
接下来需要增加修改和删除

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>部门列表</h1>
	<table>
    	<tr>
        	<th>部门编号</th>
        	<th>部门名称</th>
        	<th>部门地址</th>
        	<th>操作</th>
    	</tr>

    	<c:forEach items="${list}" var="dept" varStatus="index">
        	<tr>
            	<td>${index.count}</td>
            	<td>${dept.name}</td>
            	<td>${dept.location}</td>
            	<td align="center">
                <a href="/edit.do?id=${dept.id}">修改</a>
                <a href="/delete.do?id=${dept.id}">删除</a>
            </td>
        	</tr>
    	</c:forEach>
    	
	</table>
</body>
</html>

修改的时候我们是带着id传到edit的,我们就应该想办法获取这个参数。
因为新增和修改是同一个方法,所以需要有一个判断
在这里插入图片描述
因此,edit.jsp也要改一下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<center>
<h1>部门编辑</h1>
<form action="/saveOrUpdate.do" method="post">
    <input type="hidden" name="id" value="${dept.id}">
    部门名称:<input type="text" name="name" value="${dept.name}"/><br/>
    部门地址:<input type="text" name="location" value="${dept.location}"/><br/>
    <input type="submit" value="保存"/>
</form>
</center>
</body>
</html>

这个时候,saveOrUpdate还需要加个判断,用来区分新建和修改
在这里插入图片描述
删除类似的做一下,就可以了,很简单
在这里插入图片描述
crud都已经实现了,接下来需要完成的是登录功能。
首先,创建一个登录页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/login.do" method="post">
    用户姓名:<input type="text" name="username"/><br/>
    用户密码:<input type="text" name="password"/><br/>
    <input type="submit" value="登录"/>
</form>
</body>
</html>

然后创建一个UserController.java
然后创建一个IUserservice.java
然后创建一个UserServiceImpl.java
在这里插入图片描述
在这里插入图片描述
然后发现少一个servlet的依赖

	<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>

在这里插入图片描述
要记得在web.xml里面加一个欢迎页
在这里插入图片描述
登录是做到了,但是还是可以直接访问list.do
所以我们需要增加一个拦截器
如图新建
在这里插入图片描述
其实拦截器的原理很简单,进行一个判断,登陆过了,放行,没有登陆过就让他回去登录,不让直接访问页面。
在这里插入图片描述
但是想让他执行,我们还需要在springMVC.xml配置拦截器

	<!--拦截器-->
    <mvc:interceptors>
        <!--登录检查拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="text.ssm.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

但是运行以后不管输的对还是错,都会回到login.html
为什么呢?如何所示
在这里插入图片描述
按照运行顺序,你还没有set,就要get,一定是没有的,所以对的也被拦截了。
所以可以这样,只有请求LoginController的时候可以绕过拦截器,请求其他controller的时候都需要通过拦截器

	<!--拦截器-->
    <mvc:interceptors>
        <!--登录检查拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/login.do"/>
            <bean class="text.ssm.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

接下来我们想要完成一个多条件查询的功能。什么是多条件查询呢?如图
在这里插入图片描述
其实就是可以输入部门名称还有部门地址两个条件进行查询,当然多几个条件也是可以的,道理是一样的,写两个就够了。
我们要想在页面显示,肯定就要改一下list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>

   
</head>
<body>
<center>
    <h1>部门列表</h1>

    <form id="searchForm" action="/query.do" method="post">
        部门名称:<input type="text" name="deptName">
        部门地址:<input type="text" name="deptLocation">
        <input type="submit" value="搜索">

<a href="/edit.do">新增</a>
<table border="1px" width="60%">
    <tr>
        <th>部门编号</th>
        <th>部门名称</th>
        <th>部门地址</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${pageInfo.list}" var="dept" varStatus="index">
        <tr>
            <td align="center">${index.count}</td>
            <td align="center">${dept.name}</td>
            <td align="center">${dept.location}</td>
            <td align="center">
                <a href="/edit.do?id=${dept.id}">修改</a>
                <a href="/delete.do?id=${dept.id}">删除</a>

            </td>
        </tr>
    </c:forEach>
</table>
</form>
</center>
</body>
</html>

然后在DepartmentController中就需要加入一个方法
我们需要接受两个文本框写入的东西,所以就要创建一个对象来接收

@Setter@Getter@ToString
public class QueryObject {

	//前台传过来的请求参数的参数名
    private String deptName;

    private String deptLocation;
    
}

Controller只做三件事,接收请求参数,调用业务方法,控制页面跳转,共享数据。
在这里插入图片描述
所以新方法是这样的
这个时候要记得在service实现类里面把query方法实现一下
但是我们在实现过程中发现,没有这个方法
在这里插入图片描述
实际上我们是需要调用mapper里面的query方法,但是现在mapper里面没有query方法,所以我们需要去创建,直接Alt+回车创建
在这里插入图片描述
在这里插入图片描述
mapper接口中的方法要去对应一个mapper映射文件中的sql语句

	<select id="query" resultMap="departmentMap">
        SELECT * FROM department
        <where>

            <if test="deptName != null and deptName != ' '">
                and name LIKE CONCAT('%',#{deptName},'%')
            </if>

            <if test="deptLocation != null and deptLocation != ' '">
                AND location LIKE CONCAT('%',#{deptLocation},'%')
            </if>
        </where>

    </select>

为了优化,我们把QueryObject,java修改一下

@Setter@Getter@ToString
public class QueryObject {

    private String deptName;

    private String deptLocation;

    public String getDeptName() {

        return StringUtils.isNullOrEmpty(this.deptName)?null:this.deptName;

    }

    public String getDeptLocation() {

        return StringUtils.isNullOrEmpty(this.deptLocation)?null:this.deptLocation;
    }
}

所以就可以

	<select id="query" resultMap="departmentMap">
        SELECT * FROM department
        <where>

            <if test="deptName != null">
                and name LIKE CONCAT('%',#{deptName},'%')
            </if>

            <if test="deptLocation != null">
                AND location LIKE CONCAT('%',#{deptLocation},'%')
            </if>
        </where>

    </select>

但是为了可以完成回显

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>

   
</head>
<body>
<center>
    <h1>部门列表</h1>

    <form id="searchForm" action="/query.do" method="post">
        部门名称:<input type="text" name="deptName" value="${qo.deptName}">
        部门地址:<input type="text" name="deptLocation" value="${qo.deptLocation}">
        <input type="submit" value="搜索">

<a href="/edit.do">新增</a>
<table border="1px" width="60%">
    <tr>
        <th>部门编号</th>
        <th>部门名称</th>
        <th>部门地址</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${pageInfo.list}" var="dept" varStatus="index">
        <tr>
            <td align="center">${index.count}</td>
            <td align="center">${dept.name}</td>
            <td align="center">${dept.location}</td>
            <td align="center">
                <a href="/edit.do?id=${dept.id}">修改</a>
                <a href="/delete.do?id=${dept.id}">删除</a>

            </td>
        </tr>
    </c:forEach>
</table>
</form>
</center>
</body>
</html>

多条件完成以后,我们要去完成分页。分页一般分成两种情况,一种叫做物理分页,一种叫做内存分页。
在这里插入图片描述
这是我百度出来的,逻辑分页其实也就是内存分页
我们去做的是真正的物理分页
目标是实现这个要求
在这里插入图片描述
所以在list.jsp里面增加一些代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>

    <script>

       function goPage(page){
            //设置当前页的值
            if(page==0){
                document.getElementById("currentPage").value=1;
            }else{
                document.getElementById("currentPage").value=page;
            }
            //提交表单
            var form = document.getElementById("searchForm");
            form.submit();//提交表单
        }

    </script>
</head>
<body>
<center>
    <h1>部门列表</h1>

    <form id="searchForm" action="/query.do" method="post">
    	<input type="hidden" name="currentPage" value="" id="currentPage"/>
        部门名称:<input type="text" name="deptName" value="${qo.deptName}">
        部门地址:<input type="text" name="deptLocation" value="${qo.deptLocation}">
        <input type="submit" value="搜索">

<a href="/edit.do">新增</a>
<table border="1px" width="60%">
    <tr>
        <th>部门编号</th>
        <th>部门名称</th>
        <th>部门地址</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${pageInfo.list}" var="dept" varStatus="index">
        <tr>
            <td align="center">${index.count}</td>
            <td align="center">${dept.name}</td>
            <td align="center">${dept.location}</td>
            <td align="center">
                <a href="/edit.do?id=${dept.id}">修改</a>
                <a href="/delete.do?id=${dept.id}">删除</a>

            </td>
        </tr>
    </c:forEach>

    <tr align="center">
        <td colspan="4">

            <a href="javascript:void(0);" onclick="goPage(1)">首页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.prePage})">上页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.nextPage})">下页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.pages})">尾页</a>

        <input type="text" name="currentPage" id="currentPage" value="${qo.currentPage}">&nbsp&nbsp<input type="submit" value="跳转">

        每页显示:
        <select name="pageSize" onchange="goPage(1)">
            <option value="2" ${qo.pageSize == 2?'selected':''}>2</option>
            <option value="3" ${qo.pageSize == 3?'selected':''}>3</option>
            <option value="5" ${qo.pageSize == 5?'selected':''}>5</option>
        </select>

        当前${pageInfo.pageNum}页/共${pageInfo.pages}页/共${pageInfo.total}条
        </td>
    </tr>
</table>
</form>
</center>
</body>
</html>

然后

package text.ssm.query;

import com.mysql.jdbc.StringUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


@Setter@Getter@ToString
public class QueryObject {


    private Integer currentPage=1;

    private Integer pageSize=2;

    private String deptName;

    private String deptLocation;

    public String getDeptName() {

        return StringUtils.isNullOrEmpty(this.deptName)?null:this.deptName;

    }

    public String getDeptLocation() {

        return StringUtils.isNullOrEmpty(this.deptLocation)?null:this.deptLocation;
    }
}

这时候有一个分页插件,是一个mybatis的分页插件,只有使用mybatis框架的时候才可以使用,叫做PageHelper

	<!--mybatis分页插件-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.2</version>
    </dependency>

还要在mybatis的配置文件中配置拦截器插件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>


    <!--配置延迟加载-->
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
        <setting name="lazyLoadTriggerMethods" value=""/>
    </settings>



    <plugins>
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">

        </plugin>
    </plugins>

    
</configuration>

因为在setvice的实现类里面调用了mapper,所以

 	/*pageHelper分页插件的使用*/
    public pageInfo query2(QueryObject qo){
        PageHelper.startPage(qo.getCurrentPage(),qo.getPageSize());
        List<Department> list = mapper.query(qo);
        PageInfo pageInfo=new PageInfo(list);
        return pageInfo;
    }

DepartmentController底下也要改咯

	@RequestMapping("/query")
    public String query(@ModelAttribute("qo") QueryObject qo, Model model){

        //调用业务的方法执行查询
        /*List<Department> list = service.query(qo);
        model.addAttribute("list",list);*/
        PageInfo pageInfo = service.query2(qo);
        model.addAttribute("pageInfo",pageInfo);
        return "department/list";
    }

目前其实完成了首页,上页,下页,尾页,我还要继续优化一下,完成跳转的设置。
这个其实很简单,比如想要跳转到第二页,只需要把2传过去,还是当时设置的pagesize也传过去就可以了。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>

    <script>

       function goPage(page){
            //设置当前页的值
            if(page==0){
                document.getElementById("currentPage").value=1;
            }else{
                document.getElementById("currentPage").value=page;
            }
            //提交表单
            var from = document.getElementById("searchForm");
            from.submit();//提交表单
        }

    </script>
</head>
<body>
<center>
    <h1>部门列表</h1>

    <form id="searchForm" action="/query.do" method="post">
        部门名称:<input type="text" name="deptName" value="${qo.deptName}">
        部门地址:<input type="text" name="deptLocation" value="${qo.deptLocation}">
        <input type="submit" value="搜索">

<a href="/edit.do">新增</a>
<table border="1px" width="60%">
    <tr>
        <th>部门编号</th>
        <th>部门名称</th>
        <th>部门地址</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${pageInfo.list}" var="dept" varStatus="index">
        <tr>
            <td align="center">${index.count}</td>
            <td align="center">${dept.name}</td>
            <td align="center">${dept.location}</td>
            <td align="center">
                <a href="/edit.do?id=${dept.id}">修改</a>
                <a href="/delete.do?id=${dept.id}">删除</a>

            </td>
        </tr>
    </c:forEach>

    <tr align="center">
        <td colspan="4">

            <a href="javascript:void(0);" onclick="goPage(1)">首页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.prePage})">上页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.nextPage})">下页</a>
            <a href="javascript:void(0);" onclick="goPage(${pageInfo.pages})">尾页</a>

        <input type="text" name="currentPage" id="currentPage" value="${qo.currentPage}">&nbsp&nbsp<input type="submit" value="跳转">

        每页显示:
        <select name="pageSize" onchange="goPage(1)">
            <option value="2" ${qo.pageSize == 2?'selected':''}>2</option>
            <option value="3" ${qo.pageSize == 3?'selected':''}>3</option>
            <option value="5" ${qo.pageSize == 5?'selected':''}>5</option>
        </select>

        当前${pageInfo.pageNum}页/共${pageInfo.pages}页/共${pageInfo.total}条
        </td>
    </tr>
</table>
</form>
</center>
</body>
</html>

我们基本就搞定了,接下来总结一下分页功能实现的流程图
在这里插入图片描述
以上就是我对于SSM项目的一个简单梳理,代码没有做一个整合,是因为我之前自己做过,链接也在一开始就说了。java菜鸟,刚刚入行,如果有哪里不对,欢迎指正,谢谢!

发布了189 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/NewBeeMu/article/details/103875146
今日推荐