常用依赖
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- 打包时跳过测试-->
<skipTests>true</skipTests>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- 作用域 -->
<scope>runtime</scope>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!-- 作用域 -->
<scope>test</scope>
</dependency>
<!-- 实体类使用@Data -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- swagger2测试-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- json工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
</dependencies>
<build>
<!-- 打jar包插件 maven>双击package -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
常用配置
server:
port: 8888
servlet:
context-path: /stest #路径名
#应用名称
spring:
jeckson:
date-format: yyyy-MM-dd hh:mm:ss
time-zone: GTM+8 #后台返回前台时间处理 hh:mm:ss解决后台返回前台时间不一致
redis:
port: 63792
host: 127.0.0.1
password: 123456
application:
name: spider
datasource:
name: yinxun #数据库名
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false #假如时区报错,就增加一个时区配置?serverTimezone=UTC
username: root #用户名
password: 123456 #密码
driver-class-name: com.mysql.cj.jdbc.Driver #数据库链接驱动
#mybatis-plus
mybatis-plus:
mapper-locations: classpath:mapper/*.xml #配置映射文件 自定义时使用
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志打印
lucenePath: F:/tmp/lucene/ #别的地方可通过@Value取得
启动类
@EnableTransactionManagement//事务管理
@EnableScheduling//开启定时任务
@MapperScan("com.liulang.xx.mapper")//扫描包,也可以放在mybatis-plus 上
@SpringBootApplication
public class SssApp {
public static void main(String[] args) {
SpringApplication.run(SssApp.class,args);
}
}
mybatis-plus 使用
依赖(pom)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
(application.yml)
#mybatis-plus
mybatis-plus:
mapper-locations: classpath:mapper/*.xml #配置映射文件 自定义时使用
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志打印
配置类
@Configuration
@MapperScan("com.yx.spider.dao.mapper")
public class MybatisPlusConfig {
//分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor =new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
使用例子
查询
// 根据id 查询
SysUser sysUser = sysUserMapper.selectById(id);
//查询一条
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getAccount,account);
queryWrapper.eq(SysUser::getPassword,password);
queryWrapper.select(SysUser::getAccount,SysUser::getId,SysUser::getAvatar,SysUser::getNickname);
queryWrapper.last("limit 1");//表示在sql语句末尾添加 查询一条可以不使用
SysUser sysuser =sysUserMapper.selectOne(queryWrapper);
//查询多条
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Article::getViewCounts);
queryWrapper.select(Article::getId,Article::getTitle);
queryWrapper.last("limit "+limit);//注意limit后加空格
List<Article> articles = articleMapper.selectList(queryWrapper);
//快捷使用
List<BannerItem> bannerItems = new LambdaQueryChainWrapper<>(bannerItemMapper)
.eq(BannerItem::getBannerId, id)
.list();
BannerItem bannerItem = new LambdaQueryChainWrapper<>(bannerItemMapper)
.eq(BannerItem::getId, id)
.one();
// queryWraper 单条语句之间,默认使用and
// 使用 or 时如下
queryWraper.and(i -> i.like(Article::getTitle, "%"+finalKeywords).or().like(Article::getKeyWords,"%"+finalKeywords));
添加
SysUser sysUser = new SysUser();
sysUser.setAccount(userParms.getAccount());
sysUser.setNickname(userParms.getNickname());
sysUserMapper.insert(sysUser);
//添加完后可获得数据库生成 id
Long id = sysUser.getId();
修改
//查询
SysUser sysUser = sysUserMapper.selectById(id);
//修改
sysUser.setAccount(userParms.getAccount());
sysUserMapper.updateById(sysUser)
删除
// 单个删除
sysUserMapper.deleteById(id);
// 批量删除
ArrayList<Long> integers = new ArrayList<>();
integers.add()。。。
。。。。//获得 id 列表
sysUserMapper.deleteBatchIds(integers);
swagger测试 使用
依赖
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
配置类
/**
* @ClassName SwaggerConfig
* @Description 访问地址 http://127.0.0.1:8081/swagger-ui.html
**/
@Configuration//配置到配置里
@EnableSwagger2 //开启swagger
public class SwaggerConfig {
}
使用
//访问地址 http://127.0.0.1:8081/swagger-ui.html 在Controller类添加注解
@Api(tags = "用户管理")
@RestController
@RequestMapping("users")
public class UserController {
。。。
@ApiOperation("获取当前用户信息")
@GetMapping("currentUser")
public Result currentUser(@RequestHeader("Authorization") String token )
常见问题
解决跨域
在 Controller 类 上加注解 @CrossOrigin
后端返回前端时间少一天(8小时)
-
配置文件修改
spring: jeckson: date-format: yyyy-MM-dd hh:mm:ss time-zone: GTM+8 #后台返回前台时间处理 hh:mm:ss
-
实体类中对date类型进行注解序列化
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd hh:mm:ss")
对象中相同数据转化
import org.springframework.beans.BeanUtils;
//将 article 与articlevo 中相同属性转换
BeanUtils.copyProperties(article,articleVo);
WebMvc配置拦截器
自定义拦截器
/**
* @ClassName LoginInterceptor
* 登陆拦截器 也可以自定义实现权限控制
**/
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private LoginService loginService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//在执行controller方法(Handler)之前进行执行
if (!(handler instanceof HandlerMethod)){
//handler 可能是 RequestResourceHandler springboot 程序 访问静态资源 默认去classpath下的static目录去查询
return true;
}
//获取token
String token = request.getHeader("Authorization");
//日志打印
log.info("=================request start===========================");
String requestURI = request.getRequestURI();
log.info("request uri:{}",requestURI);
log.info("request method:{}",request.getMethod());
log.info("token:{}", token);
log.info("=================request end===========================");
if (StringUtils.isBlank(token)){
Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(JSON.toJSONString(result));
return false;
}
SysUser sysUser = loginService.checkToken(token);
if (sysUser == null){
Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(JSON.toJSONString(result));
return false;
}
return true;
}
}
将拦截器加入配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry){
//拦截所有除了/login /swagger*/** /error
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login")
.excludePathPatterns("/swagger*/**")
.excludePathPatterns("/error");
}
}
定时任务
springboot 自带实现
-
在启动类上添加注解 @EnableScheduling//开启定时任务
-
在 ServiceImpl 具体方法上添加 @Scheduled
//开启定时 每月第一天 12 点执行 @Scheduled(cron = "0 0 12 1 * ?")
任务开启,关闭,线程实现
Controller
/**
* @ClassName DynamicTaskController
**/
@Api(tags = "定时任务")
@RestController
@CrossOrigin
@RequestMapping("task")
public class DynamicTaskController {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler; //任务线程池
@Autowired
private Scheme2Mapper scheme2Mapper;
private Map<Long,ScheduledFuture<?>> taskMap = new HashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
return new ThreadPoolTaskScheduler();
}
@PostMapping("startCron")
@ApiOperation("开始定时任务")
public Result startCron(@RequestBody TaskParms taskParms) throws InterruptedException {
String task = taskParms.getTask();
Long corn = taskParms.getCorn();
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(new MyRunable1(task), new Trigger() {
//定时任务触发器
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// return new CronTrigger(corn).nextExecutionTime(triggerContext);
// return new PeriodicTrigger(2, TimeUnit.SECONDS).nextExecutionTime(triggerContext);
return new PeriodicTrigger(corn, TimeUnit.HOURS).nextExecutionTime(triggerContext);
}
});
List<String> response_list = MyRunable1.response_list;//执行信息列表
//修改 方案状态
Scheme2 scheme2 = scheme2Mapper.selectById(taskParms.getId());
scheme2.setStatus(1);
//方案 定时
scheme2.setCorn(corn);
scheme2Mapper.updateById(scheme2);
// taskParms.getId() 必须唯一
taskMap.put(taskParms.getId(),schedule);
return Result.success();
}
@PostMapping("stopCron")
@ApiOperation("关闭定时任务")
public Result stopCron(@RequestParam("id") Long id) {
if (taskMap.get(id) != null) {
taskMap.get(id).cancel(true);//定时任务关闭
}
//修改 方案状态
Scheme2 scheme2 = scheme2Mapper.selectById(id);
scheme2.setStatus(0);
scheme2Mapper.updateById(scheme2);
taskMap.remove(id);
return Result.success();
}
}
具体任务 MyRunable1
/**
* @ClassName MyRunable1
* 定时任务1
**/
public class MyRunable1 implements Runnable{
@Autowired
private SiteMapper siteMapper;
public static List<String> response_list;
private static String task;
public MyRunable1(String task1) {
this.task = task1;
}
@Override
public void run() {
。。。。//任务内容
}
}
事务处理
- 在启动类上添加注解 @EnableTransactionManagement//事务管理
- 在 ServiceImpl 具体方法上添加 @Transactional//开启事务
JWT生成工具类
依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
package com.test.spider.utils;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JWTUtils {
//秘钥
private static final String jwtToken = "654123yqwe!@#$$";
public static String createToken(Long userId){
Map<String,Object> claims = new HashMap<>();
claims.put("userId",userId);
JwtBuilder jwtBuilder = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, jwtToken) // 签发算法,秘钥为jwtToken
.setClaims(claims) // body数据,要唯一,自行设置
.setIssuedAt(new Date()) // 设置签发时间
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 60 * 1000));// 一天的有效时间
String token = jwtBuilder.compact();
return token;
}
public static Map<String, Object> checkToken(String token){
try {
Jwt parse = Jwts.parser().setSigningKey(jwtToken).parse(token);
return (Map<String, Object>) parse.getBody();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
//生成token
String token = JWTUtils.createToken(100L);
System.out.println(token);
//获取token中的用户id
Map<String, Object> map = JWTUtils.checkToken(token);
System.out.println(map.get("userId"));
}
}
设置全局返回结果
Result
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @ClassName Result
* @Description 定义全局返回结果
**/
@Data
@AllArgsConstructor//使用后添加一个构造函数,该构造函数含有所有已声明字段属性参数
public class Result {
private boolean success;
private int code;
private String msg;
private Object data;
public static Result success(Object data){
return new Result(true,200,"success",data);
}
public static Result success(){
return new Result(true,200,"success",null);
}
public static Result success(String msg){
return new Result(true,200,msg,null);
}
public static Result fail(int code,String msg){
return new Result(false,code,msg,null);
}
}
ErrorCode
public enum ErrorCode {
PARAMS_ERROR(10001,"参数有误"),
ACCOUNT_PWD_NOT_EXIST(10002,"用户名或密码错误"),
TOKEN_ERROR(10003,"token不合法"),
ACCOUNT_EXIST(10004,"账号已存在"),
PARAMS_NOEXIST(10007,"参数不存在"),
ACCOUNT_PWD_NOT_NULL(10005,"账户或密码不能为空"),
ACCOUNT_FORBIDDEN(10006,"用户被禁用"),
ARTICLE_REPORT_ERROR(30001,"文章已上报"),
ARTICLE_WARN_ERROR(40001,"文章已预警"),
NO_PERMISSION(70001,"无访问权限"),
SESSION_TIME_OUT(90001,"会话超时"),
NO_LOGIN(90002,"未登录"),
SYSTENM_ERROR(-999,"系统异常");
private int code;
private String msg;
ErrorCode(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
设置统一异常处理
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @ClassName AllExceptionHandler
* @Description 统一异常处理
**/
@ControllerAdvice
public class AllExceptionHandler {
//进行异常处理,处理Exception.class的异常
@ExceptionHandler(Exception.class)
@ResponseBody
public Result doException(Exception ex){
return Result.fail(ErrorCode.SYSTENM_ERROR.getCode(), ErrorCode.SYSTENM_ERROR.getMsg());
}
}
MD5加密
import org.apache.commons.codec.digest.DigestUtils;
password = DigestUtils.md5Hex(password+slat);//salt 加密盐
连接redis
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置
spring:
redis:
port: 63792
host: 127.0.0.1
password: 123456
使用
@Autowired
private RedisTemplate<String,String> redisTemplate;
//存入redis
redisTemplate.opsForValue().set("TOKEN_"+token, JSON.toJSONString(sysUser),1, TimeUnit.DAYS);//设置过期时间1天
//从redis中取出
String userJson = redisTemplate.opsForValue().get("TOKEN_"+token)
//redis 删除对应的key
redisTemplate.delete("TOKEN_"+token);
json 与对象转换
//将 对象转化为 json 字符串
String s = JSON.toJSONString(sysUser);
//将 string 转化为 对象
SysUser sysUser = JSON.parseObject(userJson,SysUser.class);
后端接收前端 数据
接收json 数据 进行解析
通用方式一
{
"enterprise": {
"code": "qwerr",
"id": 10000,
"name": "xx"
},
"first_name": "张",
"last_name": "三",
"mail": "xx.com",
"phone": "1111111"
}
单格式的JSON如上,后端接收接收json字符串的时候使用(@RequestBody String data) String类型,然后用JSONObject转换成对应的实体类 给逻辑层去处理。
import com.alibaba.fastjson.JSONObject;
public Result login(@RequestBody JSONObject data){
//获得mail
String mail = (String) data.get("mail");
//获得 name
HashMap<String,String> enterprise = (HashMap)data.get("enterprise");
String name = enterprise.get("name");
方式二
创建实体类 使用实体对象接收
public Result list(@RequestBody ArticleListParms articleListParms)
接收路径上数据
@GetMapping("/{id}")
public Result queryArticleById(@PathVariable("id") Long id)
接收表单数据
@PostMapping("deleteBatch")
public Result deleteBatchIds(@RequestParam("ids") String ids )
接收请求头数据
public Result logout(@RequestHeader("Authorization") String token)