因为工作原因,需要写SSM项目,但是好久没弄这块了,都忘得差不多了,看着密密麻麻的代码很是绝望。还好自己之前有写过SSM项目,打算通过把自己的简单项目重新梳理一遍,来达到恢复记忆的目的,正好也在这里和大家分享一下。
之前整理的文章在我的博客里里有,链接如下:https://blog.youkuaiyun.com/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