首页 > 其他分享 >springboot整合security+jwt

springboot整合security+jwt

时间:2023-05-06 20:44:42浏览次数:35  
标签:springboot INTO jwt sys token VALUES user security NULL

一、引入相关依赖

<!--spring security依赖-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <!--jwt依赖-->
  <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
  </dependency>
  <!--常用工具类依赖-->
  <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
  </dependency>
  <!--hutool工具类-->
  <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.9</version>
  </dependency>

二、在application.yml中配置相关信息

security:
  jwt:
    expire: 604800
    secret: admin
    header: Authorization

三、添加jwtutil工具类


@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "security.jwt")
public class JwtUtil {
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    private String secret;
    private Long expire;

    /**
     * 根据负责生成JWT的token
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

    /**
     * 生成token的过期时间
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expire * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetailImpl userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     */
    public String generateToken(UserDetailImpl userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    /**
     * 判断token是否可以被刷新
     */
    public boolean canRefresh(String token) {
        return !isTokenExpired(token);
    }

    /**
     * 刷新token
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}

/**
 * response响应头等信息设置
 */
public class WebUtils {

    public static String renderString(HttpServletResponse response,String string){
        try{
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().println(string);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

四、编写UserDetails实现类UserDetailImpl


@Data
@NoArgsConstructor
public class UserDetailImpl implements UserDetails {
    private SysUser user;
    private List<String> permission;

    public UserDetailImpl(SysUser user, List<String> permission) {
        this.user = user;
        this.permission = permission;
    }

    @JSONField(serialize = false)
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return permission.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

五、编写UserDetailsService实现类UserDetailsServiceImpl


@Slf4j
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    SysUserMapper userMapper;

    @Autowired
    SysMenuMapper sysMenuMapper;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //根据用户名查询用户信息
        SysUserExample sysUserExample = new SysUserExample();
        sysUserExample.createCriteria().andUsernameEqualTo(s);
        List<SysUser> sysUsers = userMapper.selectByExample(sysUserExample);
        //判断是否存在
        if(sysUsers == null || sysUsers.size() == 0 ){
            throw new RuntimeException("用户名或密码错误");
        }
        //存在再把用户权限信息查询出来
        SysUser sysUser = sysUsers.get(0);
        log.info("当前用户信息为>>>{}"+sysUser);
        List<String> menus = sysMenuMapper.selectMenusByUserId(sysUser.getId());
        //封装到UserDetails对象中去,并返回
        return new UserDetailImpl(sysUser,menus);
    }
}

六、编写登录接口login

    @PostMapping("/login")
    public ResultVo login(@RequestBody User user){
        String token = userService.login(user.getUsername(),user.getPassword());
        Map<String, String> map = new HashMap<>();
        //返回前端token对应的key,这里用的Authorization
        map.put("key",header);
        //返回前端的token值
        map.put("token",token);
        return ResultVo.succ(map);
    }

七、在登录实现类接口中进行相关认证操作


@Service
public class SysUserListImpl implements SysUserService {
    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    RedisUtil redisUtil;
    @Override
    public ResultVo selectUserList() {
        List<SysUser> users = userMapper.selectByExample(null);
        return ResultVo.succ(users);
    }

    @Override
    public String login(String username, String password) {
        //将前端传入的用户名、密码封装到UsernamePasswordAuthenticationToken对象中
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username,password);
        //调用AuthenticationManager的authenticate方法,将usernamepassword传入
        //security会自动调用我们写的UserDetailServiceImpl类中的loadUserByUsername方法
        //去数据库中查找用户信息,进行认证,认证结果会封装到authenticate中
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        //判断是否认证成功
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }
        //认证成功则根据用户名等信息生成token
        UserDetailImpl user = (UserDetailImpl) authenticate.getPrincipal();
        String token = jwtUtil.generateToken(user);
        //用户信息存redis
        redisUtil.set("login:"+user.getUser().getUsername(),user);
        return token;
    }
}

八、配置认证失败处理器AuthenticationEntryPointImpl


/**
 * 认证失败处理器
 */
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        //封装认证失败信息
        ResultVo resultVo = new ResultVo(HttpStatus.UNAUTHORIZED.value(), "认证失败,请重新登录", null);
        String result = JSON.toJSONString(resultVo);
        WebUtils.renderString(httpServletResponse,result);
    }
}

九、配置自定义token过滤器


/**
 * token过滤器
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${security.jwt.header}")
    private String header;

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    RedisUtil redisUtil;
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        //获取请求头中的token
        String token = httpServletRequest.getHeader(header);
        if(StringUtils.isEmpty(token)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        //解析token
        String username = jwtUtil.getUserNameFromToken(token);
        if(StringUtils.isEmpty(username)){
            throw new RuntimeException("token异常");
        }
        //从redis查询用户信息
        UserDetailImpl userDetail = (UserDetailImpl) redisUtil.get("login:" + username);
        //存入SecurityContext中
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

十、 配置无权访问处理器AccessDeniedImpl


/**
 * 无访问权限
 */
@Component
public class AccessDeniedImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        //封装无访问权限信息
        ResultVo resultVo = new ResultVo(HttpStatus.FORBIDDEN.value(), "无访问权限", null);
        String result = JSON.toJSONString(resultVo);
        WebUtils.renderString(httpServletResponse,result);
    }
}

十一、配置securityConfig


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //放行白名单,根据需求自行添加
    public static final String[] WHITE_URL = {
        "/sys-user/login"
    };

    @Autowired
    AuthenticationEntryPointImpl authenticationEntryPointImpl;

    @Autowired
    AccessDeniedImpl accessDeniedImpl;

    @Autowired
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //security跨域开启
                .cors()
                .and()
                //csrf关闭
                .csrf().disable()
                //session关闭
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                //放行白名单
                .authorizeRequests()
                .antMatchers(WHITE_URL).permitAll()
                .anyRequest().authenticated()
                .and()
                //异常处理器
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPointImpl)
                .accessDeniedHandler(accessDeniedImpl)
                .and()
                //自定义过滤器
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 暴露AuthenticationManager
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 加密方式
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

十二、授权接口通过注解来实现

    /**
     * @PreAuthorize("hasAuthority('sys:user:list')")表示拥有sys:user:list权限才可以访问
     * @param num
     * @param size
     * @return
     */
    @PreAuthorize("hasAuthority('sys:user:list')")
    @GetMapping("/selectUserList")
    public ResultVo selectUserList(Integer num,Integer size){
        PageHelper.startPage(num,size);
        return userService.selectUserList();
    }

十三、对应数据库表设计

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `username` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `password` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `email` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `city` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `created` datetime(0) NULL DEFAULT NULL,
  `updated` datetime(0) NULL DEFAULT NULL,
  `last_login` datetime(0) NULL DEFAULT NULL,
  `statu` int(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `UK_USERNAME`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '刘备', '$2a$10$evqEBqCgh1chs/9LP5MORuVzHIN.AH9.wGoB69t2SfX6Uowjb1Qo6', NULL, NULL, NULL, NULL, NULL, NULL, 1);
INSERT INTO `sys_user` VALUES (2, '关羽', '$2a$10$evqEBqCgh1chs/9LP5MORuVzHIN.AH9.wGoB69t2SfX6Uowjb1Qo6', NULL, NULL, NULL, NULL, NULL, NULL, 1);
INSERT INTO `sys_user` VALUES (3, '张飞', '$2a$10$evqEBqCgh1chs/9LP5MORuVzHIN.AH9.wGoB69t2SfX6Uowjb1Qo6', NULL, NULL, NULL, NULL, NULL, NULL, 1);
INSERT INTO `sys_user` VALUES (4, '赵云', '$2a$10$evqEBqCgh1chs/9LP5MORuVzHIN.AH9.wGoB69t2SfX6Uowjb1Qo6', NULL, NULL, NULL, NULL, NULL, NULL, 1);
INSERT INTO `sys_user` VALUES (5, '马超', '$2a$10$R7t7j0.OM/J6EgQGaXQ7.OavYHffX9SnNbnCoJD49ySbAb1A5k9x2', NULL, NULL, NULL, NULL, NULL, NULL, 1);

DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `remark` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注',
  `created` datetime(0) NULL DEFAULT NULL,
  `updated` datetime(0) NULL DEFAULT NULL,
  `statu` int(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `name`(`name`) USING BTREE,
  UNIQUE INDEX `code`(`code`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '系统管理员', 'admin', NULL, NULL, NULL, 1);
INSERT INTO `sys_role` VALUES (2, '用户管理员', 'users', NULL, NULL, NULL, 1);
INSERT INTO `sys_role` VALUES (3, '角色管理员', 'roles', NULL, NULL, NULL, 1);
INSERT INTO `sys_role` VALUES (4, '菜单管理员', 'menus', NULL, NULL, NULL, 1);
INSERT INTO `sys_role` VALUES (5, '系统工具', 'tools', NULL, NULL, NULL, 1);

DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(0) NULL DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
  `name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `path` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单URL',
  `perms` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
  `component` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `type` int(0) NOT NULL COMMENT '类型     0:目录   1:菜单   2:按钮',
  `icon` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单图标',
  `orderNum` int(0) NULL DEFAULT NULL COMMENT '排序',
  `created` datetime(0) NULL DEFAULT NULL,
  `updated` datetime(0) NULL DEFAULT NULL,
  `statu` int(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (1, NULL, '系统管理员', '', 'sys:manage', '', 0, 'el-icon-s-operation', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (2, 1, '用户管理员', '/sys/users', 'sys:user:list', '', 0, 'el-icon-s-custom', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (3, 1, '角色管理员', 'sys/roles', 'sys:role:list', '', 0, 'el-icon-rank', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (4, 1, '菜单管理员', '/sys/menus', 'sys:menu:list', '', 0, 'el-icon-menu', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (5, NULL, '系统工具', '/sys/tools', 'sys:tool:list', '', 0, 'el-icon-tool', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (6, NULL, '添加用户', '', 'sys:user:save', '', 2, '', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (7, NULL, '编辑用户', '', 'sys:user:update', '', 2, '', NULL, NULL, NULL, 1);
INSERT INTO `sys_menu` VALUES (8, NULL, '删除用户', '', 'sys:user:delete', '', 2, '', NULL, NULL, NULL, 1);

DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(0) NOT NULL,
  `role_id` bigint(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2, 2);
INSERT INTO `sys_user_role` VALUES (3, 3, 3);
INSERT INTO `sys_user_role` VALUES (4, 4, 4);
INSERT INTO `sys_user_role` VALUES (5, 5, 5);
INSERT INTO `sys_user_role` VALUES (6, 5, 2);
INSERT INTO `sys_user_role` VALUES (7, 5, 3);

DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(0) NOT NULL,
  `menu_id` bigint(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 102 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES (1, 1, 1);
INSERT INTO `sys_role_menu` VALUES (2, 1, 2);
INSERT INTO `sys_role_menu` VALUES (3, 1, 3);
INSERT INTO `sys_role_menu` VALUES (4, 1, 4);
INSERT INTO `sys_role_menu` VALUES (5, 1, 5);
INSERT INTO `sys_role_menu` VALUES (6, 1, 6);
INSERT INTO `sys_role_menu` VALUES (7, 1, 7);
INSERT INTO `sys_role_menu` VALUES (8, 1, 8);
INSERT INTO `sys_role_menu` VALUES (9, 2, 2);
INSERT INTO `sys_role_menu` VALUES (10, 3, 3);
INSERT INTO `sys_role_menu` VALUES (11, 4, 4);
INSERT INTO `sys_role_menu` VALUES (12, 5, 5);

十四、进行相关测试(其中用的的redisUtil工具类相关代码看整合redis部分)

标签:springboot,INTO,jwt,sys,token,VALUES,user,security,NULL
From: https://www.cnblogs.com/wlfs000000/p/17378408.html

相关文章

  • SpringBoot集成RocketMQ
    添加pom.xml依赖<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.2.3</version></dependency>创建消息消费者@Component@Slf4jpublicclass......
  • 【SpringBoot】【六】 刷新上下文
    1 前言上节我们看了上下文的创建和准备,那么我们这节就来看看刷新上下文。2 刷新上下文首先就是我们的run方法,执行刷新上下文  refreshContext(context)://###run方法refreshContext(context);//###SpringApplicationprivatevoidrefreshContext(ConfigurableApp......
  • 【SpringBoot】【五】 创建、准备上下文
    1 前言上节我们看了下环境准备,那么接下来我们就要看重头了,就是创建和准备上下文了。//创建上下文context=createApplicationContext();//加载异常解析报告类exceptionReporters=getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[......
  • SpringBoot 操作 MongoDB 新增和查询
    MongoDBJAVA新增+查询上接SpringBoot整合MongoDB,记一下MongoDB的CRUD方法。Create新增使用MongoRepository方式的新增非常简单,之前的整合中已经尝试过,这里再总结一下:首先需要有对应的实体类对象:@Data@AllArgsConstructor@NoArgsConstructor@ToStringpublicc......
  • 聊聊关于,SpringBoot写后端接口
    前言:一个后端接口大致分为四个部分组成:接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response)。如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但一个优秀的后端接口和一个糟糕的后端接口对比起来差异还是蛮大的,其中最重要的关键点就是......
  • SpringBoot 自动扫描第三方包及spring.factories失效的问题
    为什么会找不到Spring依赖注入就是要让spring找到要注入的类并且识别到了@Component、@Service等注解。1.当在开发的第三方包里写明了@Component、@Service等等2.引入了包,不论第三方库的引入,还是本地jar。总之是要引入到工程的这时候还加入不到IOC容器,那就说明Spri......
  • Springboot 系列 (30) - Springboot+HBase 大数据存储(八)| Springboot Client/Server
    Kerberos(SecureNetworkAuthenticationSystem,网络安全认证系统),是一种网络认证协议,其设计目标是通过密钥系统为Client/Server提供强大的认证服务。该认证过程的实现不依赖于主机操作系统的认证,无需基于的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被......
  • 解决iframe嵌套不同域报错问题:SecurityError: Blocked a frame with origin
    Error:Failedtoresolveasynccomponentdefault:SecurityError:Blockedaframewithorigin"https://223.82.12.165:8282"fromaccessingacross-originframe. 原始需求,我提供一个免登陆的链接跳转到页面A。实现需求:用一个新的工程B实现权限校验,校验成功后通过loc......
  • IDEA编写的SpringBoot项目修改后自动编译刷新
    问题的描述:       IDEA编写传统web应用使用外置的Tomcat时候,IDEA设置了外置的Tomcat的编译刷新,前端代码修改后是可以自动编译,页面刷新就能看到效果的。而开发SpringBoot项目的时候,因为它使用的是内置的Tomcat,所以即使是在html页面上修改内容,也必......
  • java基于springboot+vue的校园新闻网站、校园新闻管理系统,附源码+数据库+文档+PPT,适合
    1、项目介绍校园新闻网站的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、新闻类型管理、校园新闻管理、留言板管理、论坛交流、系统管理,用户前台:首页、校园新闻、论坛交流、留言反馈、个人中心、后台管理等功能。由于本网站的功能模块设计比较全面,所......