pom.xml:>>>>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
parent>
----------------------------------------------------
<dependency> <groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency> <groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.13version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.5version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>
⭐mapper/UserMapper.java接口
public interface UserMapper {
//查询
User selectOne(String userName);
User selectId(int userId);
//插入
int insert(User user);
//删除
int delete(int userId);
}
⭐service/UserService.java接口和UserServiceImp.java实现类
//------------------接口------------------------------
public interface UserService {
User findOne(String name);
User findId(Integer id);
void add(User user);
void drop(Integer id);
}
//-----------------实现类-----------------------------
@Service
public class UserServiceImp implements UserService{
@Autowired(required = false)
private UserMapper userMapper;
//通过用户名查找
@Override
public User findOne(String name) {
return userMapper.selectOne(name);
}
//通过id查询用胡
@Override
public User findId(Integer id) {
return userMapper.selectId(id);
}
//添加插入
@Override
public void add(User user) {
//可能是空数据引入插件
AccessUtil.isOK(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
//判断用户id
AccessUtil.isOK(StringUtils.isBlank(user.getUserPwd()),"密码不能为空");
//查询是否重复
User users=findOne(user.getUserName());
AccessUtil.isOK(users!=null,"用户名不能重复");
//判断插入是否成共
AccessUtil.isOK(userMapper.insert(user)<1,"插入失败");
}
//删除
@Override
public void drop(Integer id) {
AccessUtil.isOK(id==null || findId(id)==null,"删除记录不存在~");
//判断是否删除成功
int num=userMapper.delete(id);
AccessUtil.isOK(num<1,"删除失败!");
}
}
⭐controller/UserController.java
@RestController
public class SpringTest {
@Autowired
private UserService userService;
@GetMapping("test")
public String test(){
return "is ok";
}
//查询
@GetMapping("select/{name}")
public User selectOne(@PathVariable("name") String name){
return userService.findOne(name);
}
//查询
@GetMapping("selectid/{userId}")
public User selectid(@PathVariable("userId") Integer userId){
return userService.findId(userId);
}
//插入
@GetMapping("insert")
public CheckMsg insert(User user){
CheckMsg cm=new CheckMsg();
//捕获异常
try{
userService.add(user);
cm.setCode(100);
cm.setMsg("插入成功");
}catch (CheckException ce){
cm.setCode(ce.getCode());
cm.setMsg(ce.getMsg());
}catch (Exception e){
cm.setMsg(e.getMessage());
}
return cm;
}
//删除
@RequestMapping("delete/{userId}")
public CheckMsg delete(@PathVariable("userId") int userId){
CheckMsg cm=new CheckMsg();
//捕获异常
try{
userService.drop(userId);
cm.setCode(100);
cm.setMsg("删除成功");
}catch (CheckException ce){
cm.setCode(ce.getCode());
cm.setMsg(ce.getMsg());
}catch (Exception e){
cm.setMsg(e.getMessage());
}
return cm;
}
@GetMapping("page")
public PageInfo<User> pageSelect(PageQuery pq){
return userService.PageSelect(pq);
}
}
⭐resources/mappers/UserMapper.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.yjxxt.mapper.UserMapper">
<!-- 插入-->
<insert id="insert">
insert into user (userName,userPwd) values (#{
userName},#{
userPwd})
</insert>
<!-- 删除操作-->
<delete id="delete">
delete from user where userId=#{
userId}
</delete>
<!-- 查询-->
<select id="selectOne" resultType="com.yjxxt.bean.User">
select * from user where userName=#{
userName}
</select>
<!-- Id查询-->
<select id="selectId" resultType="com.yjxxt.bean.User">
select * from user where userId=#{
userId}
</select>
</mapper>
⭐以上便实现了简单的增删查改,还差一点~~~
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
dependency>
⭐自定义异常类:exceptions/CheckException.java
public class CheckException extends RuntimeException{
private int code=101;
private String msg="发生异常》》》》";
//重载构造器,get和set方法自己不全~!!!
public CheckException() {
super("发生异常》》》》");
}
public CheckException(int code){
super("发生异常》》》》");
this.code=code;
}
public CheckException(String msg){
super(msg);
this.msg=msg;
}
public CheckException(String msg,int code){
super(msg);
this.msg=msg;
this.code=code;
}
}
⭐com.yjxxt.util/CheckMsg.java自定义状态码对象:
public class CheckMsg {
//状态码
private int code=100;
private String msg="插入成功";
//自动补全set 、get方法
}
⭐com.yjxxt.util/AccessUtil.java对异常的间接调用
public class AccessUtil {
//静态方法进行数据审核
public static void isOK(boolean bl,String msg){
if(bl){
throw new CheckException(msg);
}
}
}
Bean/User.java这里字段与数据库最好同步
public class User implements Serializable {
private String userName;
private Integer userId;
private String userPwd;
}
启动类:>>>>>
@SpringBootApplication
@MapperScan("com.yjxxt.mapper")//扫描mapper下内容
public class Starter {
public static void main(String[] args) {
SpringApplication.run(Starter.class,args);
}
}
简单的浏览器测试一个:
根据用户名查询:
总体上即完成了Mybatis的集成,也实现了异常的处理,还有PostMan辅助软件进行Rest风格URL测试,最后呢,想到此,应该有人发现貌似修改这个能力没有编写,这里直接省略,与插入的编写类似,不做多解释~~
在企业 web 应用开发中,对服务器端接口进行测试,通常借助接口测试工具,这里使用 Postman 接口测试工具来对后台 restful 接口进行测试。
Postman 工具下载地址 : https://www.getpostman.com/apps ,选中对应平台下载即可。
下载安装后,启动 Postman 根据后台接口地址发送响应请求即可对接口进行测试。
⭐自定义:query包/PageQuery.java
public class PageQuery {
//第几页
private Integer pageNum;
//显示几条
private Integer pageTotle;
//查找的用户户名
private String userName;
//get set toString 构造器记得生成!!!此处略
}
⭐mapper/UserMapper.java
public interface UserMapper {
//分页查找
List<User> pageQuery(PageQuery pg);
}
⭐service/UserService.java和UserServiceImp.java
public interface UserService {
PageInfo<User> PageSelect(PageQuery pq);
}
//--------------------UserServiceImp.java------------
@Service
public class UserServiceImp implements UserService{
@Autowired(required = false)
private UserMapper userMapper;
//分页查找
@Override
public PageInfo<User> PageSelect(PageQuery pq) {
//进行分页初始化分页规则
PageHelper.startPage(pq.getPageNum(),pq.getPageTotle());
List<User> luser=userMapper.pageQuery(pq);
//进行分页
PageInfo<User> pagelist=new PageInfo<User>(luser);
System.out.println(pagelist.isHasNextPage());
System.out.println(pagelist.getPageNum());
System.out.println(pagelist.isHasPreviousPage());
return pagelist;
}
}
⭐controller/UserController.java
@RestController
public class SpringTest {
@Autowired
private UserService userService;
@GetMapping("page")
public PageInfo<User> pageSelect(PageQuery pq){
return userService.PageSelect(pq);
}
}
mappers/UserMapper.java:Sql语言的编写
<?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.yjxxt.mapper.UserMapper">
<!-- 分页查找-->
<select id="pageQuery" resultType="com.yjxxt.bean.User">
-- 如果没有输入userName参数,则查询全部数据
-- select * from user where userName like %{
userName}%
select * from user
<where>
<if test="userName!=null and userName!=''">
and userName like "%${userName}%"
</if>
</where>
</select>
</mapper>
pageNum:第几页,pageTotle:显示几条,userName:查询用户的名字
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
API配置类config/swagger2.java
package com.yjxxt.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.yjxxt.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("用户管理接口API文档")
.version("1.0")
.build();
}
}
@Api:用在请求的类上,说明该类的作用
tags="说明该类的作用"
----------------------------------------------
@Api(tags="APP用户注册Controller")
@ApiOperation:"用在请求的方法上,说明方法的作用"
value="说明方法的作用"
notes="方法的备注说明"
-----------------------------------------------
@ApiOperation(value="用户注册",notes="手机号、密码都是必填项,年龄是选填项,但必须是数字")
@ApiImplicitParams:用在请求的方法上,包含一组参数说明
@ApiImplicitParam:用在 @ApiImplicitParams 注解中,指定一个请求参数的配置信息
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
@ApiImplicitParams({
@ApiImplicitParam(name="mobile",value="手机 号",required=true,paramType="form"),
@ApiImplicitParam(name="password",value="密 码",required=true,paramType="form"),
@ApiImplicitParam(name="age",value="年 龄",required=true,paramType="form",dataType="Integer"
) })
@ApiResponses:用于请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
---------------------------------------------
@ApiOperation(value = "select请求", notes = "多个参数,多种的查询参数类型")
@ApiResponses({
@ApiResponse(code=400, message="请求参数没填好"),
@ApiResponse(code=404, message="请求路径没有或页面跳转路径不对")
})
@ApiModel:用于响应类上,表示一个返回响应数据的信息
(这种一般用在post创建的时候,使用@RequestBody这样的场景, 请求参数无法使用@ApiImplicitParam注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性
@ApiModel(description= "返回响应数据")
public class RestMessage implements Serializable{
@ApiModelProperty(value = "是否成功")
private boolean success=true;
@ApiModelProperty(value = "返回对象")
private Object data;
@ApiModelProperty(value = "错误编号")
private Integer errCode;
@ApiModelProperty(value = "错误信息")
private String message;
/* getter/setter */
}
User.java类加入API注解
@ApiModel(description = "响应结果-用户信息")
public class User implements Serializable {
@ApiModelProperty(value = "用户名")
private String userName;
@ApiModelProperty(value = "用户id",example = "0")
private Integer userId;
@ApiModelProperty(value = "用户密码")
private String userPwd;
}
controller层/UserController.java
//此处只给这三个方法增夹了API注解,其余类似
@RestController
public class SpringTest {
@Autowired
private UserService userService;
@ApiOperation(value = "测试springboot环境是否正常")
@GetMapping("test")
public String test(){
return "is ok";
}
//查询
@ApiOperation(value = "根据用户名查询用户信息")
@ApiImplicitParam(name = "name",value = "查询参数",required = true,paramType = "path")
@GetMapping("select/{name}")
public User selectOne(@PathVariable("name") String name){
return userService.findOne(name);
}
//查询
@ApiOperation(value = "根据用户ID获取用户信息")
@ApiImplicitParam(name = "userId",value = "查询参数",required = true,paramType = "path")
@GetMapping("selectid/{userId}")
@CachePut(value = "users", key = "#userId")
public User selectid(@PathVariable("userId") Integer userId){
return userService.findId(userId);
}
}
启动项目,访问地址浏览器访问 :http://localhost:8081/springboot/swagger-ui.html
做过 web 项目开发的对于单元测试都并不陌生了,通过它能够快速检测业务代码功能的正确与否,SpringBoot 框架对单元测试也提供了良好的支持,来看 SpringBoot 应用中单元测试的使用。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
src/Test/java/com/yjxxt/bean/ServiceTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
Starter.class})
public class ServiceTest {
@Autowired
private UserService userService;
@Before
public void before(){
System.out.println("before........");
}
@Test
public void test(){
System.out.println(userService.findId(4));
}
@After
public void after(){
System.out.println("after........");
}
}
–
新建测试类ControllerTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
Starter.class})
@AutoConfigureMockMvc
public class ControllerTest {
private Logger log = LoggerFactory.getLogger(ControllerTest.class);
@Autowired
private MockMvc mockMvc;
//用户列表查询
@Test
public void apiTest01() throws Exception{
// 构建请求
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.get("/page")
.contentType("text/html")
// 指定请求的contentType头信息
.accept(MediaType.APPLICATION_JSON);
// 指定请求的Accept头信息
// 发送请求,获取请求结果
ResultActions perform = mockMvc.perform(request);
// 请求结果校验
perform.andExpect(MockMvcResultMatchers.status().isOk());
// 表示执行完成后返回相应的结果
MvcResult mvcResult = perform.andReturn();
// 得到执行后的响应
MockHttpServletResponse response = mvcResult.getResponse();
log.info("响应状态:{}", response.getStatus());
log.info("响应内容:{}", response.getContentAsString());
}
// 用户名记录查询
@Test
public void apiTest02() throws Exception{
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/select/wang"))
. andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
log.info("响应状态:{}",mvcResult.getResponse().getStatus());
log.info("响应内容:{}",mvcResult.getResponse().getContentAsString());
}
}
EhCache 是一个比较成熟的 Java 缓存框架,最早从 hibernate 发展而来, 是进程中的缓存系统,它提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的 cache 管理方案,快速简单。
Spring Boot 对 Ehcache 的使用提供支持,所以在 Spring Boot 中只需简单配置即可使用 Ehcache 实现数据缓存处理。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcacheartifactId>
dependency>
<ehcache name="mycache">
<diskStore path="C:\java\cache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
defaultCache>
<cache
name="users"
eternal="false"
maxElementsInMemory="100"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU"/>
ehcache>
用于标注在类上,可以存放该类中所有缓存的公有属性,比如设置缓存的名字
@CacheConfig(cacheNames = "users")
public interface UserService {。。。}
//用于读取数据的方法上
@Cacheable(value = "user", key = "#id")
User selectUserById(final Integer id);
//用于写数据的方法上
@CachePut(value = "user", key = "#user.id")
public User save(User user) { users.add(user); return user; }
//用于移除数据的方法上
@CacheEvict(value = "user", key = "#id")
void delete(final Integer id);
//组合多个 Cache 注解使用
@Caching(
put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.age")
}
}
自动装配时,如果一个接口的实现类不止一个,则用@Resource指定名字装配,一个则使用@Autowired装配
UserService.java/selectid方法
@Service
public class UserServiceImp implements UserService{
@Autowired(required = false)
private UserMapper userMapper;
//通过id查询用胡
@Override
@CachePut(value = "users", key = "#id")
public User findId(Integer id) {
return userMapper.selectId(id);
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
configuration>
plugin>
devtools 可以实现页面热部署(即页面修改后会立即生效,这个可以直接在 application.properties文件中配置 spring.thymeleaf.cache=false 来实现),实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。即devtools 会监听 classpath 下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的。配置了后在修改 java 文件后也就支持了热启动,不过这种方式是属于项目重启(速度比较快的项目重启),会清空 session 中的值,也就是如果有用户登陆的话,项目重启后需要重新登陆。
## 热部署配置
devtools:
restart:
enabled: true
# 设置重启的目录,添加目录的文件需要restart
additional-paths: src/main/java
# 解决项目自动重新编译后接口报404的问题
poll-interval: 3000
quiet-period: 1000
自动编译配置File -> Settings -> Compiler -> Build Project automatically
Registry 属性修改 ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running
修改接口代码 控制台打印接收的 userName 参数,ctrl+f9 键重新编译,浏览器访问
这里 Spring Boot 集成了 mybatis 框架,mybatis 底层数据访问层实现基于 jdbc 来实现,所以在Spring Boot 环境下对事务进行控制,事务实现由 Spring Boot 实现并自动配置,在使用时通过注解方式标注相关方法加入事务控制即可。
在相关方法上加上注解@Transactional()即可
@Transactional(propagation = Propagation.REQUIRED)
//全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler{
/*** 全局异常处理 返回json*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public CheckMsg exceptionHandler(Exception e){
CheckMsg resultInfo = new CheckMsg();
resultInfo.setCode(300);
resultInfo.setMsg("操作失败!");
if(e instanceof CheckException){
CheckException pe = (CheckException) e;
resultInfo.setMsg(pe.getMsg());
resultInfo.setCode(pe.getCode());
}
return resultInfo;
}
}
这里对我们的全局异常类进行测试,将ID查询直接报异常看是否能够捕获到
//查询
@ApiOperation(value = "根据用户ID获取用户信息")
@ApiImplicitParam(name = "userId",value = "查询参数",required = true,paramType = "path")
@GetMapping("selectid/{userId}")
@CachePut(value = "users", key = "#userId")
public User selectid(@PathVariable("userId") Integer userId){
//报异常
AccessUtil.isOK(true,"测试一下......");
return null;
}
常用注解校验如下:
案列演示:》》》
①、对User类添加注解
@ApiModel(description = "响应结果-用户信息")
public class User implements Serializable {
@NotBlank(message = "用户名不能为空!")
@ApiModelProperty(value = "用户名")
private String userName;
@ApiModelProperty(value = "用户id",example = "0")
private Integer userId;
@NotBlank(message = "用户ID不能为空!")
@Length(min = 6, max = 10,message = "密码长度至少6位但不超过10位!")
@ApiModelProperty(value = "用户密码")
private String userPwd;
}
//set和get方法略
②、UserController.java插入方法增加@Valid和修改
//插入
@PostMapping("insert")
public CheckMsg insert(@Valid User user){
CheckMsg cm=new CheckMsg();
// //捕获异常
// try{
userService.add(user);
cm.setCode(100);
cm.setMsg("插入成功");
// }catch (CheckException ce){
// cm.setCode(ce.getCode());
// cm.setMsg(ce.getMsg());
// }catch (Exception e){
// cm.setMsg(e.getMessage());
// }
return cm;
}
测试结果:》》》
完结撒花~~~~