SpringBoot学习案例
本机环境:
- idea 2018 年12月版本
- springboot 是 2.2.2 版本
- mysql 8.x 版本
- sdk 1.8.x 版本(即jdk)
- maven 3.6.0 版本
1、入门案例之增删改查
1.1 资料来源
BootStrap
官网、B站上的《尚硅谷 SpringBoot
视频》(视频资料是 2018 年的,这个想看的同学可以去搜一下,应该是播放量第一吧)。这里引用的是视频中的《CRUD 实验》,不过本人做了更改:
SpringBoot
版本从1.5.10 更改成了2.2.2,mysql
版本从5.7 更改成了 8.0.x,视频中没有连接数据库,我在这里使用了 Spring
框架自带的 JdbcTemplate
做了数据库的操作。
1.2 案例描述
-
**功能:**登陆、增加、删除、更新、查看
-
sql 语句:
数据库:
springboot_crud
表数据和结构:
/* Navicat Premium Data Transfer Source Server : MySql Source Server Type : MySQL Source Server Version : 80018 Source Host : localhost:3306 Source Schema : springboot_crud Target Server Type : MySQL Target Server Version : 80018 File Encoding : 65001 Date: 27/12/2019 09:06:28 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for department -- ---------------------------- DROP TABLE IF EXISTS `department`; CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `departmentName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of department -- ---------------------------- INSERT INTO `department` VALUES (101, 'D-AAa'); INSERT INTO `department` VALUES (102, 'D-BBb'); INSERT INTO `department` VALUES (103, 'D-CCc'); INSERT INTO `department` VALUES (104, 'D-DDd'); INSERT INTO `department` VALUES (105, 'D-EEe'); -- ---------------------------- -- Table structure for employee -- ---------------------------- DROP TABLE IF EXISTS `employee`; CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lastName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `gender` int(1) NULL DEFAULT NULL, `department_id` int(11) NULL DEFAULT NULL, `birth` date NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1009 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of employee -- ---------------------------- INSERT INTO `employee` VALUES (1001, 'D-AA冯', '[email protected]', 1, 101, '2019-12-25'); INSERT INTO `employee` VALUES (1002, 'D-BB', '[email protected]', 1, 102, '2019-12-25'); INSERT INTO `employee` VALUES (1003, 'D-CC', '[email protected]', 0, 103, '2019-12-25'); INSERT INTO `employee` VALUES (1006, '冯劲松', '[email protected]', 1, 102, '2019-12-23'); INSERT INTO `employee` VALUES (1007, '老冯2号', '[email protected]', 1, 103, '2019-12-23'); INSERT INTO `employee` VALUES (1008, '小张名', '[email protected]', 0, 101, '2019-12-22'); SET FOREIGN_KEY_CHECKS = 1;
1.3 项目结构
pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.feng</groupId>
<artifactId>spring-web-crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-web-crud</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
<dependencies>
<!--引入web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.3.1</version>
</dependency>
<!--模板引擎 thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<scope>provided</scope>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.3.1 resources文件夹
application.properties 文件:
# 服务器地址
# server.address=192.168.1.138
# 服务器端口
# server.port=8080
# 禁用缓存
spring.thymeleaf.cache=false
# 上下文路径
server.servlet.context-path=/crud
# 国际化
spring.messages.basename=i18n.login
# 日期格式 默认是 yyyy/MM/dd
spring.mvc.date-format=yyyy-MM-dd
# springboot2.2.x 默认不支持delete put等请求方式
# 必须在此处配置开启
spring.mvc.hiddenmethod.filter.enabled=true
application.ym 文件:
#### 数据源访问
spring:
datasource:
url: jdbc:mysql://localhost/springboot_crud?serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
1.3.2 java 文件夹
LoginHandlerInterceptor 类
package org.feng.component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Feng on 2019/12/24 13:15
* CurrentProject's name is spring-boot-learning<br>
* 做登陆检查:没有登陆的用户只能在登陆页面(不能进入其他页面)
* @author Feng
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object currentUser = request.getSession().getAttribute("currentUser");
// 未登录,返回登录页面
if(currentUser == null){
request.setAttribute("errorMessage", "没有权限,请先登录!");
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
}
return true;
}
}
MyLocalResolver 类
package org.feng.component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* Created by Feng on 2019/12/24 11:15
* CurrentProject's name is spring-boot-learning
* 本地解析器:截取请求参数,设置Local<BR>
* http://localhost:8080/crud/index.html?l=en_US
* @author Feng
*/
public class MyLocalResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] split = l.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
DruidConfig 类
package org.feng.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Feng on 2019/12/25 14:15
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
/**
* 配置 Druid 的监控
* 配置一个管理后台的 Servlet
* @return
*/
@Bean
public ServletRegistrationBean registrationBean(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
Map<String, String> initParams = new HashMap<>(16);
// 进入阿里数据监听页面时,需要输入的登陆名和密码
initParams.put("loginUsername", "feng");
initParams.put("loginPassword", "123456");
// 默认允许所有访问
initParams.put("allow", "");
bean.setInitParameters(initParams);
return bean;
}
/**
* 配置一个web监控
*/
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter());
Map<String, String> initParams = new HashMap<>(16);
initParams.put("exclusions", "*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Collections.singletonList("/*"));
return bean;
}
}
WebConfiguration 类
package org.feng.config;
import org.feng.component.LoginHandlerInterceptor;
import org.feng.component.MyLocalResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Created by Feng on 2019/12/24 9:30
* CurrentProject's name is spring-boot-learning<br>
* 一个类要扩展Springmvc,实现{@link WebMvcConfigurer}并加上{@link Configuration}注解<br>
* 不能注解{@link org.springframework.web.servlet.config.annotation.EnableWebMvc}
* @author Feng
*/
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 当浏览器访问当前项目或index.html时跳转到模板引擎的index.html页面。
registry.addViewController("/").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
/**
* 注册拦截器:拦截未登录用户
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 设置拦截路径+不拦截的路径
// 不需要设置静态资源的拦截,SpringBoot已经设置好了
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/user/login", "/**/*.js", "/**/*.css", "/**/*.svg", "/**/*.png");
}
/**
* 测试:多个{@link WebMvcConfigurer}会同时起作用
*/
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index.html").setViewName("index");
}
};
}
/**
* 本地解析器:国际化请求头设置
*/
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResolver();
}
}
Department 类
package org.feng.entities;
import lombok.*;
/**
* 部门
* @author Feng
*/
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Department {
@Getter
@Setter
private Integer id;
@Getter
@Setter
private String departmentName;
}
Employee 类
package org.feng.entities;
import lombok.*;
import java.util.Date;
/**
* 员工
* @author Feng
*/
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@Getter
public class Employee {
private Integer id;
private String lastName;
private String email;
/**
* 性别
* 1 表示male, 0 female
*/
private Integer gender;
private Department department;
private Date birth;
}
DepartmentDao 类
package org.feng.dao;
import org.feng.entities.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author Feng
*/
@Repository
public class DepartmentDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public DepartmentDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Department> getDepartments(){
String sql = "select id, departmentName from department";
return jdbcTemplate.query(sql, (resultSet, i) -> {
Department department = new Department();
department.setId(resultSet.getInt("id"));
department.setDepartmentName(resultSet.getString("departmentName"));
return department;
});
}
public Department getDepartment(Integer id){
String sql = "select id, departmentName from department where id = " + id;
return jdbcTemplate.queryForObject(sql, Department.class);
}
}
EmployeeDao 类
package org.feng.dao;
import org.feng.entities.Department;
import org.feng.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @author Feng
*/
@Repository
public class EmployeeDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public EmployeeDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save(Employee employee){
Integer id = employee.getId();
if(id != null){
update(employee);
return;
}
insert(employee);
}
private void insert(Employee employee){
String sql = "insert into employee(lastName, email, gender, department_id, birth) values (?, ?, ?, ?, ?)";
jdbcTemplate.update(sql, employee.getLastName(), employee.getEmail(), employee.getGender(),
employee.getDepartment().getId(), employee.getBirth());
}
private void update(Employee employee){
String sql = "update employee set lastName = ?, email = ?, gender = ?, department_id = ?, birth = ? where id " +
"= ?";
jdbcTemplate.update(sql, employee.getLastName(), employee.getEmail(), employee.getGender(),
employee.getDepartment().getId(), employee.getBirth(), employee.getId());
}
private Employee resultToEmp(ResultSet resultSet) throws SQLException {
Department dept = new Department();
dept.setDepartmentName(resultSet.getString("departmentName"));
Employee emp = new Employee();
emp.setId(resultSet.getInt("id"));
emp.setLastName(resultSet.getString("lastName"));
emp.setEmail(resultSet.getString("email"));
emp.setGender(resultSet.getInt("gender"));
emp.setBirth(resultSet.getDate("birth"));
emp.setDepartment(dept);
return emp;
}
public List<Employee> getAll(){
String sql = "select emp.id, lastName, email, gender, birth, departmentName " +
"from employee emp,department dept where dept.id = emp.department_id";
return jdbcTemplate.query(sql, (resultSet, rowNum) -> resultToEmp(resultSet));
}
public Employee get(Integer id){
String sql = "select emp.id, lastName, email, gender, birth, departmentName " +
"from employee emp,department dept where emp.id = " + id + " and dept.id = emp.department_id";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> resultToEmp(rs));
}
public void delete(Integer id){
String sql = "delete from employee where id = ?";
jdbcTemplate.update(sql, id);
}
}
EmpController 类
package org.feng.controller;
import org.feng.dao.DepartmentDao;
import org.feng.dao.EmployeeDao;
import org.feng.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
/**
* Created by Feng on 2019/12/24 16:13
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Controller
public class EmpController {
private final EmployeeDao employeeDao;
private final DepartmentDao departmentDao;
/**
* templates/emp/..
*/
private final String EMP_PREFIX = "emp/";
@Autowired
public EmpController(EmployeeDao employeeDao, DepartmentDao departmentDao) {
this.employeeDao = employeeDao;
this.departmentDao = departmentDao;
}
/**
* 员工列表
*/
@GetMapping("/emps")
public String list(Model model){
model.addAttribute("emps", employeeDao.getAll());
return EMP_PREFIX + "list";
}
/**
* 去增加页面
*/
@GetMapping("/emp")
public String toAddPage(Model model){
// 查找所有的部门
model.addAttribute("departments", departmentDao.getDepartments());
return EMP_PREFIX + "add";
}
@PostMapping("/emp")
public String addEmp(Employee employee){
employeeDao.save(employee);
// 重定向到列表
return "redirect:/emps";
}
@GetMapping("/emp/{id}")
public String toEditPage(@PathVariable("id") Integer id,
Model model){
model.addAttribute("emp", employeeDao.get(id));
model.addAttribute("departments", departmentDao.getDepartments());
return EMP_PREFIX + "add";
}
@PutMapping("/emp")
public String updateEmp(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
@DeleteMapping("/emp/{id}")
public String deleteEmp(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
}
UserController 类
package org.feng.controller;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
import java.util.Map;
/**
* Created by Feng on 2019/12/24 11:37
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping(value = "/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Map<String, Object> map,
HttpSession session){
final String tempPassword = "123456";
if(!StringUtils.isEmpty(username) && tempPassword.equals(password)){
session.setAttribute("currentUser", username);
return "redirect:/main.html";
}
map.put("errorMessage", "用户名或密码错误");
return "index";
}
}
注意:resources中有些文件没有列出,如下截图。
完整项目下载路径:
链接:https://pan.baidu.com/s/1cUsnQIscbzotTy1kBATd8Q
提取码:ni19
2、 SpringBoot与Redis
目的:将对象转成 String 存进 Redis
2.1 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.feng</groupId>
<artifactId>spring-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-redis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--
解决:
Error:(32, 42) java: 无法访问com.fasterxml.jackson.databind.JavaType
找不到com.fasterxml.jackson.databind.JavaType的类文件
-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 application.yml 文件
spring:
redis:
host: localhost
port: 6379
timeout: 3000
cache:
redis:
# 允许允许空值
cache-null-values: true
# 使用秘钥前缀
# use-key-prefix: true
# 条目过期时间,默认永不过期
# time-to-live: 10000
# 缓存类型。默认情况下,根据环境自动检测
type: redis
2.3 java 类
RedisConfiguration 类
package org.feng.config;
import org.feng.redis.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Created by Feng on 2019/12/26 18:40
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Configuration
public class RedisConfiguration {
@Bean
public StringRedisSerializer createStringRedisSerializer(){
return new StringRedisSerializer();
}
@Bean
public RedisTemplate createRedisTemplate(@Autowired StringRedisSerializer keySerializer,
@Autowired RedisConnectionFactory factory){
RedisTemplate<String, UserInfo> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(keySerializer);
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(UserInfo.class));
return redisTemplate;
}
}
UserInfo 类
package org.feng.redis.entity;
import lombok.*;
import java.io.Serializable;
/**
* Created by Feng on 2019/12/26 18:22
* CurrentProject's name is spring-boot-learning
* 用户实体
* @author Feng
*/
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class UserInfo implements Serializable {
private static final long serialVersionUID = -6532802857856063504L;
private Long userId;
private String nickName;
private String password;
private String tel;
}
SpringRedisApplicationTests 类
package org.feng;
import org.feng.redis.entity.UserInfo;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SpringRedisApplicationTests {
@Resource
private RedisTemplate<String, UserInfo> template;
@Test
public void testUserInfo(){
template.opsForValue().set("user:feng", new UserInfo(1001L,"小冯", "123456", "18142395136" ));
Assert.assertEquals(true, template.hasKey("user:feng"));
System.out.println(template.opsForValue().get("user:feng"));
}
}
2.4 测试结果
3、SpringBoot 与 Mybatis Plus
务必参考:点击进入
3.1 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.feng</groupId>
<artifactId>spring-mybatis-plus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-mybatis-plus</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
<scope>runtime</scope>
</dependency>
<!-- mybatisPlus 核心库 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 application.yml 文件
# 配置端口
server:
port: 8080
# 数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_mybatis_plus?useUnicode=true&serverTimezone=UTC
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# 支持post、delete等请求
mvc:
hiddenmethod:
filter:
enabled: true
# mybatis plus
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉mapper所对应的xml文件位置)
mapper-locations: classpath*:mapper/user/**Mapper.xml
# 以下配置均有默认值
global-config:
db-config:
#主键类型 auto:"数据库ID自增" 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
field-strategy: NOT_EMPTY
#数据库类型
db-type: MYSQL
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 扫描实体
type-aliases-package: org.feng.user.entity
3.3 java 类
UserInfo 类
package org.feng.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* Created by Feng on 2019/12/26 9:10
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Data
@TableName("user_info")
public class UserInfo implements Serializable {
private static final long serialVersionUID = -1264942065222132282L;
/**
* 主键
* {@code @TableId} 中可以决定主键的类型,不写会采取默认值,默认值可以在yml中配置
* AUTO: 数据库ID自增
* INPUT: 用户输入ID
* ID_WORKER: 全局唯一ID,Long类型的主键
* ID_WORKER_STR: 字符串全局唯一ID
* UUID: 全局唯一ID,UUID类型的主键
* NONE: 该类型为未设置主键类型
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 技能
*/
private String skill;
/**
* 评价
*/
private String evaluate;
/**
* 分数
*/
private Long fraction;
}
UserMapper接口
package org.feng.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.feng.user.entity.UserInfo;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by Feng on 2019/12/26 9:06
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Component
public interface UserMapper extends BaseMapper<UserInfo> {
/**
* 测试:mybatis plus 支持mybatis配置xml的方式
*/
List<UserInfo> listUserInfoByXml();
}
UserService 接口
package org.feng.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.feng.user.entity.UserInfo;
import java.util.List;
/**
* Created by Feng on 2019/12/26 9:15
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
public interface UserService extends IService<UserInfo> {
/**
* 测试:mybatis plus 支持mybatis配置xml的方式
*/
List<UserInfo> listUserInfoByXml();
}
UserServiceImpl 实现类
package org.feng.user.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.feng.user.entity.UserInfo;
import org.feng.user.mapper.UserMapper;
import org.feng.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by Feng on 2019/12/26 9:16
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserInfo> implements UserService {
private final UserMapper userMapper;
@Autowired
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<UserInfo> listUserInfoByXml() {
return userMapper.listUserInfoByXml();
}
}
MybatisPlusConfiguration 类
package org.feng.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by Feng on 2019/12/26 9:07
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@Configuration
public class MybatisPlusConfiguration {
/**
* mybatis plus SQL 执行效率插件(生产环境可以关闭)
* @return {@link PerformanceInterceptor}
*/
@Bean
public PerformanceInterceptor performanceInterceptor(){
return new PerformanceInterceptor();
}
/**
* 分页插件
* @return {@link PaginationInterceptor}
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
3.4 controller 类
UserController 类
package org.feng.user.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.feng.user.entity.UserInfo;
import org.feng.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* Created by Feng on 2019/12/26 9:19
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@RestController
@RequestMapping("/user")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
/**
* 查询所有用户信息
* @return {@link List}
*/
@GetMapping("/list")
public List<UserInfo> listUser(){
return userService.list();
}
/**
* 通过id 查询用户信息
* @param userId 用户id
* @return {@link UserInfo}
*/
@GetMapping("/detail")
public UserInfo getUser(@RequestParam("id") String userId){
return userService.getById(userId);
}
/**
* 分页查询所有数据:
* 从页面得到当前页
* @return
*/
@GetMapping("/page/{currentPage}")
public IPage<UserInfo> getPageList(@PathVariable Long currentPage){
/*
IPage<UserInfo> page = new Page<>(5, 1);
page = userService.page(page);*/
return userService.page(new Page<>(currentPage, 2));
}
/**
* 多条件查询
* @return
*/
@GetMapping("/listByMap")
public Collection<UserInfo> listByMap(){
Map<String, Object> map = new HashMap<>(16);
map.put("age", 20);
return userService.listByMap(map);
}
/**
* 新增
*/
@PutMapping("/save")
public void saveUser(@RequestBody UserInfo userInfo){
userService.save(userInfo);
}
/**
* 批量增加
*/
@GetMapping("/saveBatch")
public void saveBatch(){
UserInfo xiaoWang = new UserInfo();
xiaoWang.setName("小王");
xiaoWang.setSkill("JS");
xiaoWang.setAge(26);
xiaoWang.setFraction(97L);
xiaoWang.setEvaluate("该学生太丑了,只能写BUG啊");
UserInfo xiaoLi = new UserInfo();
xiaoLi.setName("小力");
xiaoLi.setSkill("C++");
xiaoLi.setAge(23);
xiaoLi.setFraction(54L);
xiaoLi.setEvaluate("学习太差了");
userService.saveBatch(Arrays.asList(xiaoWang, xiaoLi));
}
/**
* 根据实体中的id去更新数据,其他字段若为null,则不会更新该字段
*/
@GetMapping("/update")
public void updateUser(@RequestParam("id") Integer id,
@RequestParam("age") Integer age){
/// 通过页面传来
UserInfo userInfo = new UserInfo();
userInfo.setId(id);
userInfo.setAge(age);
userService.updateById(userInfo);
}
/**
* 新增或更新用户信息:
* id为null就会自增:新增
* id不为null就会修改
*/
@GetMapping("/saveOrUpdate")
public void saveOrUpdate(){
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setAge(33);
userService.saveOrUpdate(userInfo);
}
/**
* 通过id删除用户
* @param id
*/
@GetMapping("/delete/{id}")
public void deleteUser(@PathVariable String id){
userService.removeById(id);
}
/**
* 批量删除
* @param ids {@code 1,2,3,4} 的格式;以逗号分隔的id
*/
@GetMapping("/deleteList/{ids}")
public void deleteUserList(@PathVariable String ids){
Collection idList = Arrays.asList(ids.split(","));
userService.removeByIds(idList);
}
/**
* 多条件删除
*/
@GetMapping("/deleteMap")
public void deleteByMap(){
Map<String, Object> map = new HashMap<>(16);
map.put("skill", "删除");
map.put("fraction", 10);
userService.removeByMap(map);
}
}
QueryWrapperController 类
package org.feng.user.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.feng.user.entity.UserInfo;
import org.feng.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Created by Feng on 2019/12/26 11:00
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@RestController
@RequestMapping("/wrapper")
public class QueryWrapperController {
private final UserService userService;
@Autowired
public QueryWrapperController(UserService userService) {
this.userService = userService;
}
@GetMapping("/query1")
public List<UserInfo> query1(){
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
// 年龄等于18 分数大于等于60小于80
wrapper.lambda()
.eq(UserInfo::getAge, 18)
.ge(UserInfo::getFraction, 60)
.lt(UserInfo::getFraction, 80);
return userService.list(wrapper);
}
/**
* 模糊查询+按照年龄降序
*/
@GetMapping("/query2")
public List<UserInfo> query2(){
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.lambda()
.like(UserInfo::getSkill, "画")
.orderByDesc(UserInfo::getAge);
return userService.list(wrapper);
}
/**
* 模糊查询名字带有"小"或者年龄大于18的学生
*/
@GetMapping("/query3")
public List<UserInfo> query3(){
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.lambda()
.like(UserInfo::getName, "小")
.or()
.ge(UserInfo::getAge, 18);
return userService.list(wrapper);
}
/**
* 查询评价不为null的学生,并且分页
*/
@GetMapping("/query4")
public List<UserInfo> query4(){
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.lambda().isNotNull(UserInfo::getEvaluate);
return userService.page(new Page<>(1, 4), wrapper).getRecords();
}
}
XmlUserController 类
package org.feng.user.controller;
import org.feng.user.entity.UserInfo;
import org.feng.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Created by Feng on 2019/12/26 14:00
* CurrentProject's name is spring-boot-learning
* @author Feng
*/
@RestController
@RequestMapping("/xml")
public class XmlUserController {
private final UserService userService;
@Autowired
public XmlUserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/list")
public List<UserInfo> xmlListAll(){
return userService.listUserInfoByXml();
}
}
3.5 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="org.feng.user.mapper.UserMapper">
<select id="listUserInfoByXml" resultType="UserInfo">
select id, name, age, skill, evaluate, fraction from user_info
</select>
</mapper>
3.6 小结
这一节,大多内容是来自我标题下的那个链接。主要为学习之用。Mybatis plus 真香!!!
在继承了接口之后,可以使用很多常用的方法。配置少,在与Spring Boot 整合后,它也可以写 mybatis 的xml方式,注解方式等。建表语句我就不粘贴了,有需要的朋友可以去大佬那粘贴,我用他的表练习的。
3.7 idea 的 rest 测试
方式1:
方式2:
测试结果:
4、SpringBoot 与 JPA
参考:点击进入
4.1 目录结构
4.2 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.feng</groupId>
<artifactId>spring-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-jpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.3 application.yml 文件
spring:
datasource:
# 注意:mysql8 需要指定时区
url: jdbc:mysql://localhost:3306/springboot_jpa?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# validate 加载 hibernate 时,验证创建数据库表结构
# create 每次加载 hibernate,重新创建数据库表结构
# create-drop 加载 hibernate 时创建,退出是删除表结构
# update 加载 hibernate 自动创建或更新数据库结构
# validate 启动时验证表的结构,不会创建表
# none 启动时不做任何操作
jpa:
hibernate:
format_sql: true
ddl-auto: update
# 控制台打印sql
show-sql: true
4.4 java 类
Employee 类
package org.feng.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
/**
* Created by Feng on 2019/12/26 20:22
* CurrentProject's name is spring-boot-learning
* 实体类:与数据库表形成映射<br>
* <p>
* {@link Entity}:表示使用JPA注解配置映射关系,告诉JPA这是一个实体类。<br>
* {@link Table}:用于指定和那个数据表对应;省略时表示取类名小写
* </p>
* @author Feng
*/
@Table(name = "emp")
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
/**
* 主键:自增
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 指定列名:不为空,唯一,长度为 128
*/
@Column(name = "emp_name", nullable=false , unique = true, length = 128)
private String empName;
/**
* 邮箱:
* 当不指定 {@code @Column}时,取的是属性名作为列名
*/
private String email;
/**
* 部门编号
*/
@Column(name = "dept_id")
private Integer deptId;
}
EmpDao 接口
package org.feng.dao;
import org.feng.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* Created by Feng on 2019/12/27 10:29
* CurrentProject's name is spring-boot-learning
* JPA 需要使用接口继承{@link JpaRepository},其实现类常用的方法
* @author Feng
*/
public interface EmpDao extends JpaRepository<Employee, Integer> {
}
测试类
package org.feng;
import org.feng.dao.EmpDao;
import org.feng.entity.Employee;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.Optional;
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringJpaApplicationTests {
@Resource
private EmpDao empDao;
/**
* 保存一条数据
*/
@Test
void testSave(){
Employee emp = new Employee();
emp.setEmpName("小李");
emp.setEmail("[email protected]");
emp.setDeptId(1002);
empDao.save(emp);
}
/**
* 通过 id 查询
*/
@Test
void testQueryById(){
Optional<Employee> emp = empDao.findById(1);
emp.ifPresent(System.out::println);
}
/**
* 查询所有数据
*/
@Test
void testQueryAll(){
empDao.findAll().forEach(System.out::println);
}
@Test
void testQueryAllBySort(){
// Hibernate: select employee0_.id as id1_0_, employee0_.dept_id as dept_id2_0_, employee0_.email as email3_0_, employee0_.emp_name as emp_name4_0_ from emp employee0_ order by employee0_.emp_name asc
// 按名字排序:升序
empDao.findAll(Sort.by("empName")).forEach(System.out::println);
// 按名字排序:降序
empDao.findAll(Sort.by(Sort.Direction.DESC, "empName")).forEach(System.out::println);
/*
* select employee0_.id as id1_0_,
* employee0_.dept_id as dept_id2_0_,
* employee0_.email as email3_0_,
* employee0_.emp_name as emp_name4_0_
* from
* emp employee0_
* where
* employee0_.dept_id=1002
* order by
* employee0_.id
* asc
*/
Employee emp = new Employee();
emp.setDeptId(1002);
empDao.findAll(Example.of(emp), Sort.by("id")).forEach(System.out::println);
}
/**
* 分页:每页2条数据,当前页是第 0 页,按照 id 排序<br>
* Hibernate: select employee0_.id as id1_0_, employee0_.dept_id as dept_id2_0_, employee0_.email as email3_0_,
* employee0_.emp_name as emp_name4_0_ from emp employee0_ order by employee0_.id asc limit ?
* Hibernate: select count(employee0_.id) as col_0_0_ from emp employee0_
* Employee(id=1, empName=小冯, [email protected], deptId=1001)
* Employee(id=2, empName=小李, [email protected], deptId=1002)
*/
@Test
void testQueryPage(){
Pageable pageable = PageRequest.of(0, 2, Sort.by("id"));
empDao.findAll(pageable).get().forEach(System.out::println);
}
}