首页 > 其他分享 >80、SpringBoot3 SpringSecurity Mybatisplus最新版 整合 实现登入权限控制

80、SpringBoot3 SpringSecurity Mybatisplus最新版 整合 实现登入权限控制

时间:2024-04-16 16:23:12浏览次数:21  
标签:TableField Mybatisplus String private 登入 import new 最新版 public

1、导入pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>newversion-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </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-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--swagger测试-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.21</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

 2、编写application.yml  配置文件

server:
  port: 6666
spring:
  application:
    name: boot3-security
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security-demo
    username: root
    password: 123456
  data:
    redis:
      host: 106.54.26.206
      port: 6379

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

 3、编写启动类

@SpringBootApplication
public class NewVersionApplication {

    public static void main(String[] args) {
        SpringApplication.run(NewVersionApplication.class, args);
    }

}

4、准备工具类、通用类

package com.atguigu.newversion.utils;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import java.util.Date;

public class JwtHelper {
    // token 令牌的过期时间
    private static long tokenExpiration = 365 * 24 * 60 * 60 * 1000;
    // 令牌密钥
    private static String tokenSignKey = "123456";

    public static String createToken(Long userId, String username) {
        String token = Jwts.builder()
                .setSubject("AUTH-USER")
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .claim("userId", userId)
                .claim("username", username)
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    public static Long getUserId(String token) {
        try {
            if (StringUtils.isEmpty(token)) return null;

            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
            Claims claims = claimsJws.getBody();
            Integer userId = (Integer) claims.get("userId");
            return userId.longValue();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getUsername(String token) {
        try {
            if (StringUtils.isEmpty(token)) return "";

            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
            Claims claims = claimsJws.getBody();
            return (String) claims.get("username");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        String token = JwtHelper.createToken(1L, "admin");
        System.out.println(token);
        System.out.println(JwtHelper.getUserId(token));
        System.out.println(JwtHelper.getUsername(token));
    }
}
package com.atguigu.newversion.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import java.io.IOException;
import java.util.Map;

public class ResponseUtil {

    public static void out(HttpServletResponse response, Object result) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.atguigu.newversion.utils;

import lombok.Data;


public enum ResultCodeEnum {
    SUCCESS(200, "请求成功"),
    FAILED(500, "操作失败"),
    TOKEN_FAILED(501, "操作超时"),
    NO_PERMISSION(403, "无权限"),
    LOGOUT(502, "已退出"),
    SAFE_CHECK_FAILED(503, "此操作需要先进行安全验证"),
    NONE(100, "无");

    private int code;
    private String msg;

    private ResultCodeEnum(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;
    }

}
package com.atguigu.newversion.utils;

import lombok.Data;

import java.io.Serializable;

@Data
public class ResultData<T> implements Serializable {
    private int code;

    private String msg;

    private T data;

    public static <T> ResultData<T> success(){
        ResultData<T> resultData=new ResultData<T>();
        resultData.setMsg("操作成功");
        resultData.setCode(ResultCodeEnum.SUCCESS.getCode());
        return resultData;
    }

    public static <T> ResultData<T> success(T data){
        ResultData<T> resultData=new ResultData<T>();
        resultData.setData(data);
        resultData.setMsg("操作成功");
        resultData.setCode(ResultCodeEnum.SUCCESS.getCode());
        return resultData;
    }

    public static <T> ResultData<T> success(String msg, T data){
        ResultData<T> resultData=new ResultData<T>();
        resultData.setData(data);
        resultData.setMsg(msg);
        resultData.setCode(ResultCodeEnum.SUCCESS.getCode());
        return resultData;
    }


    public static <T> ResultData<T> error() {
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(ResultCodeEnum.FAILED.getCode());
        resultData.setMsg("系统异常");
        return resultData;
    }


    public static <T> ResultData<T> error(String msg) {
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(ResultCodeEnum.FAILED.getCode());
        resultData.setMsg(msg);
        return resultData;
    }

}

5、添加 实体类

package com.atguigu.newversion.entity.base;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
public class BaseEntity implements Serializable {

    @TableId(type = IdType.AUTO)
    private Long id;

    @TableField("create_time")
    private Date createTime;

    @TableField("update_time")
    private Date updateTime;

    @TableLogic
    @TableField("is_deleted")
    private Integer isDeleted;

    @TableField(exist = false)
    private Map<String,Object> param = new HashMap<>();
}
package com.atguigu.newversion.entity;

import com.atguigu.newversion.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.util.List;

@Data
@TableName("sys_user")
public class SysUser extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    @TableField("username")
    private String username;

    @TableField("password")
    private String password;


    @TableField("name")
    private String name;

    @TableField("phone")
    private String phone;


    @TableField("head_url")
    private String headUrl;

    @TableField("dept_id")
    private Long deptId;

    @TableField("post_id")
    private Long postId;


    @TableField("description")
    private String description;


    @TableField("open_id")
    private String openId;

    @TableField("status")
    private Integer status;

    @TableField(exist = false)
    private List<SysRole> roleList;
    //岗位
    @TableField(exist = false)
    private String postName;
    //部门
    @TableField(exist = false)
    private String deptName;
}
@Data
@TableName("sys_role")
public class SysRole extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    @TableField("role_name")
    private String roleName;

    @TableField("role_code")
    private String roleCode;

    @TableField("description")
    private String description;

}
@Data
@TableName("sys_menu")
public class SysMenu extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    @TableField("parent_id")
    private Long parentId;

    @TableField("name")
    private String name;


    @TableField("type")
    private Integer type;


    @TableField("path")
    private String path;


    @TableField("component")
    private String component;


    @TableField("perms")
    private String perms;


    @TableField("icon")
    private String icon;

    @TableField("sort_value")
    private Integer sortValue;


    @TableField("status")
    private Integer status;

    // 下级列表
    @TableField(exist = false)
    private List<SysMenu> children;
    //是否选中
    @TableField(exist = false)
    private boolean isSelect;
}
@Data
@TableName("sys_role_menu")
public class SysRoleMenu extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    @TableField("role_id")
    private Long roleId;

    @TableField("menu_id")
    private Long menuId;

}
@Data
@TableName("sys_user_role")
public class SysUserRole extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    @TableField("role_id")
    private Long roleId;

    @TableField("user_id")
    private Long userId;
}
6、编写一个继承 SpringSecurity里的User类 用于封装数据 MySecurityUser类
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

public class MySecurityUser extends User {

    /**
     * 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了)
     */
    private SysUser sysUser;

    public MySecurityUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {
        super(sysUser.getUsername(), sysUser.getPassword(), authorities);
        this.sysUser = sysUser;
    }

    public SysUser getSysUser() {
        return sysUser;
    }

    public void setSysUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }

}

7、编写一个继承Security 中的 UserDetailService接口 MyUserDetailService 用于查询用户信息和权限权限

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    private SysMenuService sysMenuService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername,username);
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        List<String> userPermsList = sysMenuService.findUserPermsList(sysUser.getId());
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (String perm : userPermsList) {
            authorities.add(new SimpleGrantedAuthority(perm.trim()));
        }
        return new MySecurityUser(sysUser, authorities);
    }
}

8、编写一个 处理登入请求的过滤器 

public class TokenLoginFilter  extends UsernamePasswordAuthenticationFilter  {

    private RedisTemplate<String,Object> redisTemplate;

    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate) {
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        //指定登录接口及提交方式,可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/user/login","POST"));
        this.redisTemplate = redisTemplate;
    }


    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {
            Map loginVo = new ObjectMapper().readValue(req.getInputStream(), Map.class);
            //这个方法让Security 去调用 UserDetailsService loadUserByUsername方法
            Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.get("username"), loginVo.get("password"));
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 登录成功
     * @param request
     * @param response
     * @param chain
     * @param auth
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
        System.out.println("《==========================登入成功=========================》");
        MySecurityUser customUser = (MySecurityUser) auth.getPrincipal();
        String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
        //保存权限数据
        redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));

        //通过response返回数据
        ResponseUtil.out(response, ResultData.success(token));
    }

    /**
     * 登录失败
     * @param request
     * @param response
     * @param e
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        System.out.println("《==========================登入失败=========================》");
        if(e.getCause() instanceof RuntimeException) {
            ResponseUtil.out(response, ResultData.error(e.getMessage()));
        } else {
            ResponseUtil.out(response, ResultData.error("登入失败用户名或密码错误"));
        }
    }

}

9、编写一个过滤所有方法的过滤器获取token 校验用户是否登入

public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private RedisTemplate redisTemplate;

    public TokenAuthenticationFilter(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("uri:"+request.getRequestURI());
        //如果是登录接口,直接放行
        if("/user/login".equals(request.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request,response);
        if(null != authentication) {
            //最终把用户的所以信息放到安全 上下文对象里面 在项目任何地方使用
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("msg", "没有登入请先登入");
            //通过response返回数据
            ResponseUtil.out(response, map);
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request,HttpServletResponse response) {
        String token = request.getHeader("token");
        if (!StringUtils.isEmpty(token)) {
            String username = JwtHelper.getUsername(token);
            Long userId = JwtHelper.getUserId(token);
            if (!StringUtils.isEmpty(username)) {
                String authoritiesString = (String) redisTemplate.opsForValue().get(username);
                if(authoritiesString == null){
                    ResponseUtil.out(response, ResultData.error("令牌已经失效请重新登入"));
                }
                List<Map> mapList = JSON.parseArray(authoritiesString, Map.class);
                List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                for (Map map : mapList) {
                    authorities.add(new SimpleGrantedAuthority((String)map.get("authority")));
                }
                return new UsernamePasswordAuthenticationToken(username, userId, authorities);
            } else {
                return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
            }
        }
        return null;
    }
}

10、编写redis的配置类

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 设置key的序列化方式为StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // 设置value的序列化方式,根据需要选择合适的序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    }

    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {

        //定义序列化器
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();


        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //过期时间600秒
                .entryTtl(Duration.ofSeconds(600))
                // 配置序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));

        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();

        return cacheManager;
    }
}

11、SpringSevurity的核心配置类

@EnableMethodSecurity
@EnableWebSecurity//@EnableWebSecurity是开启SpringSecurity的默认行为
@Configuration
public class MyWebSecurityConfig {

    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Bean
    public AuthenticationManager authenticationManager(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(myUserDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        ProviderManager providerManager = new ProviderManager(provider);
        return providerManager;
    }

    //密码加密器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(conf ->conf.requestMatchers(paths).permitAll()
                .anyRequest().authenticated())
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(conf ->conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
                .addFilter(new TokenLoginFilter(authenticationManager(),redisTemplate))
                .build();
    }


    private final String[] paths = {
            "/favicon.ico","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html","/v3/**"
    };
    @Bean
    WebSecurityCustomizer ignoredUrlsCustomizer() {
        return (web) -> web.ignoring().requestMatchers(paths);
    }

}

12、根据userID 查询用户拥有的权限数据

<?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.atguigu.newversion.mapper.SysMenuMapper">

    <resultMap id="sysMenuMap" type="com.atguigu.newversion.entity.SysMenu" autoMapping="true">
    </resultMap>

    <select id="findListByUserId" resultMap="sysMenuMap">
        select distinct
            m.id,m.parent_id,m.name,m.type,m.path,m.component,m.perms,m.icon,m.sort_value,m.status,m.create_time,m.update_time,m.is_deleted
        from sys_menu m
        inner join sys_role_menu rm on rm.menu_id = m.id
        inner join sys_user_role ur on ur.role_id = rm.role_id
        where ur.user_id=#{userId}
          and m.status = 1
          and rm.is_deleted = 0
          and ur.is_deleted = 0
          and m.is_deleted = 0
    </select>
</mapper>

 

标签:TableField,Mybatisplus,String,private,登入,import,new,最新版,public
From: https://www.cnblogs.com/shunWcs/p/18138480

相关文章

  • SpringBoot+MybatisPlus 增删改查学习第三章 (C#转JAVA)
    packagecom.example.demo;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.example.demo.entity.Person;importcom.example.demo.mapper.PersonMapper;importcom.example.demo.service.PersonService;importorg.junit.jupiter.api.Test;i......
  • centos7安装golang最新版1.21.1
    #先卸载旧的golangyumremovegolang#然后找到最新版本https://golang.google.cn/dl/#下载安装cd/usr/local/src wgethttps://golang.google.cn/dl/go1.21.1.linux-amd64.tar.gztar-zxvfgo1.21.1.linux-amd64.tar.gz-C/usr/local/#增加配置文件vim/etc/profi......
  • FL Studio 目前最新版本V21中文破解版
    FLStudioV21中文版:音乐制作的新里程碑随着数字音乐制作的快速发展,越来越多的音乐制作软件涌现出来,而FLStudio无疑是其中的佼佼者。作为一款功能强大、易于上手的音乐制作软件,FLStudioV21中文版在继承了前代版本优秀基因的基础上,进一步提升了用户体验,为音乐制作带来了......
  • 当网络攻击从“侵入”变成“登入”
    当黑客最常用的攻击手段,从用尽十八般武艺、不可告人的“侵入”,变成凭借有效账户、大摇大摆的“登入”,你会不会觉得不可思议?在2023年,这种情况已经成为常态。IBM监测了130多个国家/地区的超1500亿个安全事件形成的《2024年X-Force威胁情报指数报告》(以下简称《报告》)显示,一场围......
  • Mockito测试框架结合mybatisplus项目中第一次体验
    因为要补充单测,一般的springbootTest不是真正意义上的单测。我们需要mock数据库的连接,而不是真正的调用。所以我觉得mockito测试框架就挺好的pom引入如下代码,这里用inline是因为我要用到静态方法的调用。<dependency><groupId>org.mockito</groupId>......
  • 【javaWeb &第十二篇】MybatisPlus
    MybatisPlus详细学习快速入门MybatisPlus特性标准数据层开发分页查询按条件查询查询投影DQL编程控制DML编程控制逻辑删除乐观锁代码生成器快速入门MybatisPlus是基于Mybatis框架基础上开发的增强型工具,旨在简化开发,提高效率官方地址:http://mp.baomidou.com/开......
  • 论基于架构的软件设计方法(ABSD)及应用(系统架构师2024最新版)
    须知哈喽,大家订阅专栏后可以私信添加博主获得一对一论文,以及案例分析指导。论文可以直接背下来考试用,感谢支持 文章目录须知摘要部分:正文部分:创作指导 摘要部分:本文以某银行统一收单平台项目为例,主要论述了ABSD方法在该项目中的具体应用。2020年1月,我参与......
  • 许少辉个人简历《乡村振兴战略下传统村落文化旅游设计》2024最新版辉少许
    许少辉个人简历《乡村振兴战略下传统村落文化旅游设计》2024最新版辉少许许少辉个人简历《乡村振兴战略下传统村落文化旅游设计》2024最新版辉少许......
  • java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus
    鸿鹄工程项目管理系统SpringCloud+SpringBoot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统项目背景一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管理的提升提出了更高的要......
  • java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus
     鸿鹄工程项目管理系统SpringCloud+SpringBoot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统项目背景一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管理的提升提出了更高的......