Spring Boot +JWT +MybatisPlus,使用Token登录详细教程,附源码!

2023-11-01

一、新建Spring Boot项目
1.File→New→Module
在这里插入图片描述
2.点击下一步在这里插入图片描述
3.写完这些,点击下一步在这里插入图片描述
4.选择插件
在这里插入图片描述
5.选择项目地址,选择完成后点击Finish
在这里插入图片描述

1…创建完成后,修改pom.xml文件,添加以下依赖

<!-- MybatisPlus 核心库 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- StringUtilS工具 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>
        <!-- JSON工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.45</version>
        </dependency>
        <!-- JWT依赖 -->
        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.8.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

2.修改配置文件application.properties名称为application.yml,并创建新文件application-dev.yml
在这里插入图片描述
3.application.yml配置

spring:
  profiles:
    active: dev

4.application-dev.yml配置

server:
  port: 9099
spring:
  application:
    name: demo
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/service_data?characterEncoding=utf-8&userUnicode=true&serverTimezone=Asia/Shanghai&useSSL=false
    username: root
    password: root
    hikari:
      minimum-idle: 3
      maximum-pool-size: 5
      max-lifetime: 0
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
    default-property-inclusion: non_null
  servlet:
    multipart:
      max-file-size: 1024MB
      max-request-size: 2048MB
  #thymeleaf的配置
  thymeleaf:
    cache: false
    enabled: true
#配置mybatisplus
mybatis-plus:
  mapper-locations: classpath*:mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5.在Navicat中执行sql脚本

*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user_kmmy
-- ----------------------------
DROP TABLE IF EXISTS `user_kmmy`;
CREATE TABLE `user_kmmy`  (
  `userid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID 绝对唯一',
  `email` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户邮箱',
  `phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户手机',
  `usertype` int(10) NOT NULL DEFAULT 0 COMMENT '用户权限类型:0普通,1管理员',
  `subuser` tinyint(2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否有子账户',
  `uname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
  `passwd` char(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码',
  `isactive` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否激活',
  `salt` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '加密盐值',
  `head_img` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户头像',
  `locked` tinyint(2) NOT NULL DEFAULT 0 COMMENT '禁用账号 : 0 正常 , 1 禁用',
  `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '账号创建时间',
  `last_login_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户最后登陆时间',
  `update_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '管理员更新用户状态的时间',
  PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_kmmy
-- ----------------------------
INSERT INTO `user_kmmy` VALUES (10, '', '', 0, 0, '用户Root', '54725db42d08af904bb26647bc2b892f', 0, '2d793d799d5f4e3f9eafa9522f6b4fb2', '/images/defaultUserTitle.jpg', 0, '2020-06-05 13:43:52', '2020-06-05 13:43:52', '2020-06-05 13:43:52', NULL, NULL);

SET FOREIGN_KEY_CHECKS = 1;

6.修改主启动类,在主启动类上加上@MapperScan注解,后面跟自己的项目组名

@MapperScan(basePackages = {"com.kmmy.app*.mapper"})

三、
1.新建common包
包下创建工具类
在这里插入图片描述
MD5Utils


/**
 * @author zsj
 * 2019-08-20
 */
public class MD5Utils {
    /**
     * 使用md5的算法进行加密
     */
    public static String md5(String plainText) {
        byte[] secretBytes = null;
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(
                    plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("没有md5这个算法!");
        }
        // 16进制数字
        String md5code = new BigInteger(1, secretBytes).toString(16);
        // 如果生成数字未满32位,需要前面补0
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }

	// fdgdfgvsdfgs5e5a3c75d4e1
    public static void main(String[] args) {
        System.out.println(md5("E10ADC3949BA59ABBE56E057F20F883E"));
    }

OutputObject

/**
 * @Description: 出参对象
 * @Author: zsj
 * @CreateDate: 2019/8/16 19:43
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OutputObject implements Serializable {

    /**
     * 响应码
     */
    private String respCode;
    /**
     * 响应信息
     */
    private String respMessage;
    /**
     * 响应数据
     */
    private Object data;

    /**
     * toString
     *
     * @return
     */
    @Override
    public String toString() {
        return "OutputObject{" +
                "respCode='" + respCode + '\'' +
                ", respMessage='" + respMessage + '\'' +
                ", data=" + data +
                '}';
    }

ResultObj

/**
 * @Author: zsj
 * @Date: 2019/11/21 21:35
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultObj {

    private String respCode;
    private String respMessage;

    public static final ResultObj LOGIN_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "登陆成功");
    public static final ResultObj LOGIN_FAIL_PASS = new ResultObj(ReturnCode.FAIL, "用户名或密码错误");
    public static final ResultObj LOGIN_FAIL_CODE = new ResultObj(ReturnCode.FAIL, "验证码错误");
    public static final ResultObj THE_USER_ALREADY_EXISTS = new ResultObj(ReturnCode.FAIL, "该用户已存在");

    public static final ResultObj ADD_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "添加成功");
    public static final ResultObj  ADD_ERROR= new ResultObj(ReturnCode.FAIL, "添加失败");

    public static final ResultObj DELETE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "删除成功");
    public static final ResultObj DELETE_FAIL = new ResultObj(ReturnCode.FAIL, "删除失败");

    public static final ResultObj UPDATE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "修改成功");
    public static final ResultObj UPDATE_FAIL = new ResultObj(ReturnCode.FAIL, "修改失败");
    public static final ResultObj ILLEGAL_MOBILE_NUMBER = new ResultObj(ReturnCode.FAIL, "手机号不合法");

    public static final ResultObj RESET_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "重置成功");
    public static final ResultObj RESET_FAIL = new ResultObj(ReturnCode.FAIL, "重置失败");

    public static final ResultObj DISPATCH_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "分配成功");
    public static final ResultObj DISPATCH_FAIL = new ResultObj(ReturnCode.FAIL, "分配失败");

    public static final ResultObj BACKINPORT_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "退货成功");
    public static final ResultObj BACKINPORT_FAIL = new ResultObj(ReturnCode.FAIL, "退货失败");
    public static final ResultObj SYNCCACHE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "同步缓存成功");

    public static final ResultObj DELETE_FAIL_NEWS = new ResultObj(ReturnCode.FAIL, "删除用户失败,该用户是其他用户的直属领导,请先修改该用户的下属的直属领导,再进行删除操作");
    public static final ResultObj DELETE_QUERY = new ResultObj();


}

ReturnCode

/**
 * 响应码
 *
 * @author zhushaojie
 */
public class ReturnCode {

    /**
     * 成功
     */
    public static final String SUCCESS = "200";

    /**
     * 失败
     */
    public static final String FAIL = "400";

    /**
     * 未签证
     */
    public static final String UNAUTHORIZED = "401";

    /**
     * 未找到接口
     */
    public static final String NOT_FOUND = "404";

    /**
     * 服务器内部错误
     */
    public static final String INTERNAL_SERVER_ERROR = "500";

    /**
     * 用户默认图片
     */
    public static final String DEFAULT_IMG_USER = "/images/defaultUserTitle.jpg";

}

TokenUtil

public class TokenUtil {

    private static final long EXPIRE_TIME= 10*60*60*1000;
    private static final String TOKEN_SECRET="txdy";  //密钥盐

    /**
     * 签名生成
     * @param user
     * @return
     */
    public static String sign(UserKmmy user){
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            token = JWT.create()
                    .withIssuer("auth0")
                    .withClaim("username", user.getUname())
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(TOKEN_SECRET));
        } catch (Exception e){
            e.printStackTrace();
        }
        return token;
    }

    /**
     * 签名验证
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("认证通过:");
            System.out.println("username: " + jwt.getClaim("username").asString());
            System.out.println("过期时间:      " + jwt.getExpiresAt());
            return true;
        } catch (Exception e){
            return false;
        }
    }
}

UUIDUtils


/**
 * @author zsj
 * @version 1.0
 * @className com.deyi.govaffair.util.UUIDUtils
 * @date: 2019/8/20 10:36
 * @description TODO
 */
public class UUIDUtils {

    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-","");
    }

    public static void main(String[] args) {
        System.out.println(getUUID());
    }
}

四、新建config包
创建MybatisPlusConfig类

/**
 * @Author: zhushaojie
 * @Date: 2019/11/23 19:16
 */
@Configuration
@ConditionalOnClass(value = {PaginationInterceptor.class})
public class MybatisPlusConfig {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        logger.info("====Mybatis Plus====");
        return new PaginationInterceptor();
    }
}

WebConfiguration

/**
 * 跨域请求支持/token拦截
 * tip:只能写在一个配置类里
 */
@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    private TokenInterceptor tokenInterceptor;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    //构造方法
    public WebConfiguration(TokenInterceptor tokenInterceptor){
        this.tokenInterceptor = tokenInterceptor;
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedHeaders("*")
                .maxAge(3600)
                .allowedMethods("GET","POST","DELETE","PUT")
                .allowedOrigins("*");
        logger.info("====解决跨域问题成功!!!====");

    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer){
        configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3)));
        configurer.setDefaultTimeout(30000);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        List<String> excludePath = new ArrayList<>();
        // 排除拦截
        excludePath.add("/user/**");  //登录
        excludePath.add("/webjars/**");
        excludePath.add("/static/**");  //静态资源
        excludePath.add("/assets/**");  //静态资源
        logger.info("====通过登录拦截器====");
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

五、新建interceptor包
创建WebConfiguration类

@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
        if(request.getMethod().equals("OPTIONS")){
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }
        response.setCharacterEncoding("utf-8");
        String token = request.getHeader("token");
        if(token != null){
            boolean result = TokenUtil.verify(token);
            if(result){
                System.out.println("通过拦截器");
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try{
            JSONObject json = new JSONObject();
            json.put("msg","token verify fail");
            json.put("code","50000");
            response.getWriter().append(json.toJSONString());
            System.out.println("认证失败,未通过拦截器");
        }catch (Exception e){
            e.printStackTrace();
            response.sendError(500);
            return false;
        }
        return false;
    }
}

六、新建pojo包
创建UserKmmy实体类

/**
 * <p>
 * 用户表
 * </p>
 *
 * @author 朱少杰
 * @since 2020-06-04
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserKmmy implements Serializable {

    private static final long serialVersionUID=1L;

    /**
     * 用户ID 绝对唯一
     */
    @TableId(value = "userid", type = IdType.AUTO)
    private Long userid;

    /**
     * 用户邮箱
     */
    private String email;

    /**
     * 用户手机
     */
    private String phone;

    /**
     * 用户权限类型:0普通,1管理员
     */
    private Integer usertype;

    /**
     * 是否有子账户
     */
    private Integer subuser;

    /**
     * 用户名
     */
    private String uname;

    /**
     * 密码
     */
    private String passwd;

    /**
     * 是否激活
     */
    private Boolean isactive;

    /**
     * 加密盐值
     */
    private String salt;

    /**
     * 用户头像
     */
    private String headImg;

    /**
     * 禁用账号 : 0 正常 , 1 禁用
     */
    private Integer locked;

    /**
     * 账号创建时间
     */
    private Date createTime;

    /**
     * 用户最后登陆时间
     */
    private Date lastLoginTime;

    /**
     * 管理员更新用户状态的时间
     */
    private Date updateTime;


    public UserKmmy(String uname, String passwd) {
        this.uname = uname;
        this.passwd = passwd;
    }
}

七、创建controller包
创建UserController类

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author 朱少杰
 * @since 2020-06-04
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("login")
    @ResponseBody
    public OutputObject login(@RequestBody UserKmmy user){
        QueryWrapper<UserKmmy> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(user.getUname() != null, "uname", user.getUname());
        UserKmmy users = userService.getOne(queryWrapper);
        // 密码校验
        String s = (MD5Utils.md5(user.getPasswd()+users.getSalt()));
        if (users.getPasswd().equals(s)==false){
            return new OutputObject(ReturnCode.FAIL,"密码不正确",user);
        }
        queryWrapper.in(user.getPasswd() != null, "passwd", s);
        // 通过用户名从数据库中查询出该用户
        if (users == null){
            return new OutputObject(ReturnCode.FAIL,"用户不存在",user);
        }
        String token = TokenUtil.sign(new UserKmmy(user.getUname(),s));
        HashMap<String,Object> hs =new HashMap<>();
        hs.put("token",token);
        hs.put("userid",users.getUserid());
        return new OutputObject(String.valueOf(HttpStatus.OK.value()),"成功",hs);

    }

    /**
     * 用户注册
     * @param user
     * @return
     */
    @PostMapping("addUser")
    @ResponseBody
    public ResultObj addUser(@RequestBody UserKmmy user) {
        try {
            // 查询用户名是否存在
            QueryWrapper<UserKmmy> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("uname",user.getUname());
            UserKmmy users = userService.getOne(queryWrapper);
            if (users!=null){
                return ResultObj.THE_USER_ALREADY_EXISTS;
            }
            // 设置盐
            String salt = UUIDUtils.getUUID();
            user.setSalt(salt);
            // 设置密码加密
            String s = MD5Utils.md5(user.getPasswd()+salt);
            // 设置用户默认头像
            user.setPasswd(s);
            user.setHeadImg(ReturnCode.DEFAULT_IMG_USER);
            userService.save(user);
            return ResultObj.ADD_SUCCESS;
        } catch (Exception e) {
            e.printStackTrace();
            return ResultObj.ADD_ERROR;
        }
    }
    @RequestMapping("/index")
    public String index() {
        return "Hello World! 欢迎来到 spring boot application";
    }

}

八、创建service包
1.新建UserService接口类

/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author 朱少杰
 * @since 2020-06-04
 */
public interface UserService extends IService<UserKmmy> {

}

2.在service层下创建impl包
并创建UserServiceImpl类

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 朱少杰
 * @since 2020-06-04
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserKmmy> implements UserService {

}

九、创建mapper包
包下新建UserMapper类

public interface UserMapper extends BaseMapper<UserKmmy> {

}

十、在resources下新建mapper,在这个下面新建是为了方便idea编译
在mapper下新建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.kmmy.app.mapper.UserMapper">

</mapper>

到这里登录项目就完成了,启动项目
启动成功截图
在这里插入图片描述
测试登录,我在这里使用的postman接口测试工具进行测试

{
"uname":"用户Root",
"passwd":"1111"
}

在这里插入图片描述
到这里整个项目就结束了,有遇到问题的小伙伴可以下方评论或者关注微信公众号联系我,希望能帮助到你们!
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot +JWT +MybatisPlus,使用Token登录详细教程,附源码! 的相关文章

随机推荐

  • Windows10点击睡眠之后不锁屏?

    一些用户反馈自己在使用win10系统笔记本电脑过程中 突然碰到了无法睡眠的情况 不管是盖上屏幕还是在系统中选择睡眠 电脑都无法进行睡眠 根本没有任何反应 该怎么办呢 接下来 系统城小编就为大家带来该问题的具体解决方法 首先可以按方法一进行设
  • Deepin 系统安装并开启本地远程使Windos系统访问

    思路 1 系统安装 2 安装xrdp Linux和Windows间的远程桌面访问 coder i 的博客 CSDN博客 linux远程连接windows桌面 sudo apt install xrdp 然后启动xrdp服务 sudo sys
  • 关于stm32的GPIO的操作

    首先先了解一下输出的模式 比较常用的是 推挽输出 1 GPIO Mode AIN 模拟输入 2 GPIO Mode IN FLOATING 浮空输入 3 GPIO Mode IPD 下拉输入 4 GPIO Mode IPU 上拉输入 5 G
  • 字符流

    import java io FileNotFoundException import java io FileReader import java io FileWriter import java io IOException publ
  • 线性代数(17)——坐标转换

    坐标转换 空间的基与坐标系 任意坐标系与标准坐标系之间的转换 任意坐标系之间的转换 标准单位矩阵作为桥梁 结论验证 不使用单位坐标系为桥梁的情况 空间的基与坐标系 坐标系是理解空间的基的一个视角 如果只到了一个坐标系也相当于知道了空间中的一
  • 【axmol】基于Cocos2d-x 4.0的持续维护的游戏引擎介绍

    Axmol引擎 A Multi platform Engine for Desktop XBOX UWP and Mobile games A radical fork of Cocos2d x 4 0 Axmol是基于Cocos2d x
  • 【小程序】手动实现switch开关中带文字效果(开关左右文字相同/不同都可以)

    最终效果 左右文字宽度相同 左右文字宽度不同 左右长度相同 效果 配合wx show切换 注意 左右长度相同的话可以设置合适的相同的宽度 html
  • 五. go 常见数据结构实现原理之 string, iota

    目录 一 string 其它问题 二 iota 几个小问题 原理 一 string golang中对string的解释 8比特字节的集合 可以为空 长度为0 但不会是nil string对象不可以修改 查看string 数据结构 strin
  • C语言中的正则表达式:匹配和替换

    当你在C语言中需要进行字符串匹配和替换操作时 正则表达式是一个强大的工具 在C语言中 可以使用正则表达式库来处理正则表达式的匹配和替换操作 下面是一个使用C语言中的正则表达式的示例教程 首先 你需要包含适当的头文件 c include
  • Python之异步处理

    同步处理 也被称为是阻塞式处理 是指程序执行到某个位置 会一直等待该命令执行完毕 然后继续执行后续逻辑 异步处理 是指一段程序由多个线程或进程同时执行 从而提高软件性能 一 多线程 线程是计算机调度的基本单位 一个进程至少有一个线程 线程是
  • 计算机网络分为哪些子网,计算机网络-划分子网

    IP地址 IP地址是给因特网上的每一个主机 或路由器 的每一个接口分配一个在全世界范围是唯一的32位标识符 层次化IP地址将32位的IP地址分为网络ID和主机ID IP地址分类 分为ABCDE类地址 二进制与十进制的关系 从上图看出128以
  • 这三个普通程序员,几个月就成功转型AI,他们的经验是...

    动辄50万的毕业生年薪 动辄100万起步价的海归AI高级人才 普通员到底应不应该转型AI工程师 普通程序员到底应该如何转型AI工程师 以下 AI科技大本营精选了三个特别典型的普通程序员成功转型AI的案例 也是知乎上点赞量相当高的案例 第一案
  • 学生没有教育邮箱如何享受Jetbrains全家桶优惠(白嫖)

    学生没有教育邮箱如何享受Jetbrains全家桶优惠 白嫖 Lan 2020 04 26 10 05 351 人阅读 0 条评论 首先来一波成功图 提交申请一个星期之后终于发来了这封邮件 每次申请可以使用一年 一年之后还是学生可以继续申请
  • Vue 使用 mockjs (返回数据、get、post 请求)

    1 安装 mockjs axios 一般默认自带 没有就安装下 附 mockjs 官网 mockjs github npm install mockjs axios 一般默认自带 npm install axios 2 启动项目 根据项目环
  • C/C++

    文章目录 2 2 C语言常用关键字及运算符操作 关键字 参考 麦子学院 嵌入式C语言高级 2 2 C语言常用关键字及运算符操作 重点 掌握C语言的常用关键宇及其应用场景 使用技巧 关键字 编译器 预先定义了一定意义的字符串 32个 size
  • qt安装到指定目录

    qt everywhere src 5 12 3安装到指定目录 默认情况下 QT会自动安装到 usr local Qt目录 这对于项目工具的归类来说 总是感觉很别扭 本文仅记录自己安装的过程 同时原理可借鉴给其他的工具归类 下载qt eve
  • 传感器课程作业 车载激光雷达

    高分辨率车载3D激光雷达介绍 1 车载3D激光雷达的背景 化石能源的日渐枯竭以及气候环境的恶化使得绿色节能可持续发展理念普世流行 其中交通减排是节能减排的主要途径 加之碳中和目标的提出 新能源汽车替代传统燃油车已然成为不可逆转的趋势 各国大
  • 特别篇 :从 0 开始创作云原生应用 (殷达)

    本节内容的分享主要围绕以下两方面 介绍云原生应用是什么 介绍 Helm 和如何创作一个 Helm 应用 一 云原生应用是什么 首先我们来思考一个问题 云原生应用是什么 在生活中我们会和各种各样的应用打交道 有时候会在移动端上使用淘宝购物 使
  • 关于windows下gcc+cmake指定elf文件到特定section中

    1 map 文件中 glue 7 glue 7t是什么 Those stub sections are generated by the linker not by gcc itself so any documentation would
  • Spring Boot +JWT +MybatisPlus,使用Token登录详细教程,附源码!

    一 新建Spring Boot项目 1 File New Module 2 点击下一步 3 写完这些 点击下一步 4 选择插件 5 选择项目地址 选择完成后点击Finish 二 1 创建完成后 修改pom xml文件 添加以下依赖