springboot总结(一)

常用依赖

 <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)
上一篇:基于SpringBoot注解实现策略模式


下一篇:2022年寒假训练赛第6场