本次技术使用Springboot框架开发项目,具体使用到了国内项目开发中常见的SSM框架,springboot推荐使用的Thymeleaf模板引擎和HikariCP数据库连接池。
本次业务上做一个简单的员工管理系统,完成员工与部门的关联关系,具备基本的展示与新增功能,旨在通过本项目切入以上技术的项目搭建与使用。
首先使用IDEA创建springboot项目
选中devtools,springmvc即可,也可以直接选上mybatis、mysql、thymeleaf
pom.xml加入Mybatis依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
这里要注意,项目中加入了mybatis依赖,启动项目会报没有配置数据源的错:
解决以上问题,需要在yml中配置数据源,先把Thymeleaf依赖都加上,HikariCP在Springboot2.0后自带了,不需要在pom中加入,配置声明式事务需要用到@Aspect,所以还要加入spring的AOP依赖,此时完整的pom.xml依赖为:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
项目结构:
yml:
spring:
datasource:
username: root
password: 123
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/company?serverTimezone=UTC&characterEncoding=UTF-8
#数据库连接池
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 8
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: DatebookHikariCP
max-lifetime: 1800000
connection-timeout: 3000000
connection-test-query: select 1
#热部署
thymeleaf:
cache: false
mode: HTML5
#热部署
devtools:
restart:
enabled: true
#mvc:
#static-path-pattern: /static/**
server:
port: 8090
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.qr.empboot.entity
初学者如果不想用数据库连接池,可以直接去以上关于Hikari配置去掉即可,不影响使用。
启动类,需要注意的是要加上@MapperScan注解,告诉要扫表的MyBatis的Mapper文件所在位置:
@SpringBootApplication
//@ComponentScan("com.qr.empboot")
@MapperScan("com.qr.empboot.dao")
public class EmpbootApplication {
public static void main(String[] args) {
SpringApplication.run(EmpbootApplication.class, args);
}
}
实体类
public class Employee {
private int id;
private String name;
private String sex;
private int age;
private Department dep;
public Employee() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Department getDep() {
return dep;
}
public void setDep(Department dep) {
this.dep = dep;
}
}
public class Department {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
springmvc:
@Controller
public class EmployeeController {
@Autowired
EmployeeService empService;
@Autowired
DepartmentService departmentService;
@RequestMapping("add")
private String add(Employee emp) {
boolean flag = empService.add(emp);
if (flag) {
return "redirect:emp";
} else {
return "redirect:showAdd";
}
}
@RequestMapping("update")
private String update(Employee emp) {
boolean flag = empService.update(emp);
if (flag) {
return "redirect:emp";
} else {
return "redirect:showUpdate";
}
}
@RequestMapping("delete")
private String delete(int id) {
boolean flag = empService.delete(id);
return "redirect:emp";
}
@RequestMapping("showAdd")
private ModelAndView showAdd(ModelAndView mv) {
List<Department> deps = departmentService.search();
mv.setViewName("add");
mv.addObject("deps",deps);
return mv;
}
@RequestMapping("showUpdate")
private ModelAndView showUpdate(int id) {
ModelAndView mv = new ModelAndView("update");
List<Department> depList = departmentService.search();
//Employee emp = empService.search(id);
Employee emp = empService.searchEmpAndDep2(id);
mv.addObject("emp", emp);
return mv;
}
@RequestMapping("search")
public ModelAndView search() {
ModelAndView mv = new ModelAndView("emp");
List<Employee> list = empService.search();
list.add(new Employee());
mv.addObject("list", list);
return mv;
}
@RequestMapping("testJson")
@ResponseBody
public List<Employee> testJson() {
List<Employee> list = empService.search();
return list;
}
}
dao层
@Repository
public interface EmployeeDao {
public List<Employee> search();
public Employee searchEmpAndDep(int id);
public int add(Employee emp);
public Employee searchById(int id);
public int update(Employee emp);
public int delete(int id);
Employee searchEmpAndDep2(int id);
}
public interface DepartmentDao {
public List<Department> search();
public Department searchById(int id);
}
Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qr.empboot.dao.EmployeeDao">
<select id="search" resultType="Employee">
select * from
employee
</select>
<select id="searchById" resultType="Employee">
select * from
employee where id=#{id}
</select>
<insert id="add">
insert into
employee(name,sex,age)values(#{name},#{sex},#{age})
</insert>
<update id="update">
update employee set
name=#{name},age=#{age},sex=#{sex} where
id=#{id}
</update>
<delete id="delete">
delete from employee where
id=#{id}
</delete>
<select id="searchEmpAndDep" resultType="Employee">
select e.*,d.id as 'dep.id',d.name as 'dep.name' from
employee as e left join department as d on e.d_id=d.id where e.id=#{id}
</select>
<select id="searchEmpAndDep2" resultMap="EmpAndDep2">
select * from
employee where id=#{id}
</select>
<resultMap id="EmpAndDep2" type="Employee">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="sex" column="sex"></result>
<result property="age" column="age"></result>
<association property="dep" javaType="Department" column="d_id" select="com.qr.empboot.dao.DepartmentDao.searchById">
</association>
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qr.empboot.dao.DepartmentDao">
<select id="search" resultType="Department">
select * from
department
</select>
<select id="searchById" resultType="Department">
select * from
department where id=#{id}
</select>
</mapper>
service层没有自己的业务,省略
声明式事务
@Aspect
@Configuration
public class TransactionAdviceConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.***.service.*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("add*", txAttr_REQUIRED);
source.addTransactionalMethod("save*", txAttr_REQUIRED);
source.addTransactionalMethod("delete*", txAttr_REQUIRED);
source.addTransactionalMethod("update*", txAttr_REQUIRED);
source.addTransactionalMethod("exec*", txAttr_REQUIRED);
source.addTransactionalMethod("set*", txAttr_REQUIRED);
source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
System.out.println("********************88ddd*************");
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
Thymeleaf:
emp.html
<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.thymeleaf.org">
<head >
<meta charset="UTF-8">
<title>Title</title>
<script th:src="@{/jquery-3.1.0.js}"></script>
<link th:href="@{/bootstrap/css/bootstrap.css}" rel="stylesheet"/>
</head>
<body>
<div style="width:400px;margin:20px auto">
<table class="table table-bordered">
<tr>
<th>id</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
<tr th:each="emp:${list}">
<td th:text="${emp.id}"></td>
<td th:text="${emp.name}"></td>
<td th:text="${emp.sex}"></td>
<td th:text="${emp.age}"></td>
</tr>
</table>
</div>
</body>
</html>
add.html
<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.thymeleaf.org">
<head >
<meta charset="UTF-8">
<title>Title</title>
<script th:src="@{/jquery-3.1.0.js}"></script>
<link th:href="@{/bootstrap/css/bootstrap.css}" rel="stylesheet"/>
</head>
<body>
<
<div style="width:500px;margin: 20px auto">
<form class="form-horizontal" action="add" method="post">
<div class="form-group">
<label class="col-sm-2 control-label">名字</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" placeholder="请输入名字">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="sex" placeholder="请输入性别">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">年龄</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" placeholder="请输入年龄">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-10">
<select class="form-control" name="deps" >
<option th:each="dep:${deps}" th:value="${dep.id}" th:text="${dep.name}"></option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-10">
<select class="form-control" name="deps" >
<option th:each="dep:${deps}" th:value="${dep.id}" th:text="${dep.name}"></option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">保存</button>
</div>
</div>
</form>
</div>
</body>
</html>