亿级高并发电商项目-- 实战篇 --万达商城项目 六(编写角色管理、用户权限(Spring Security认证授权)、管理员管理等模块)

news2024/11/25 11:57:24

  

专栏:高并发---前后端分布式 

👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人 

编写角色服务接口

接下来我们编写角色相关的CRUD方法,首先在通用模块编写角色服务接口:

public interface RoleService {
    // 新增角色
    void add(Role role);
    // 修改角色
    void update(Role role);
    // 删除角色
    void delete(Long id);
    // 根据id查询角色
    Role findById(Long id);
    // 查询所有角色
    List<Role> findAll();
    // 分页查询角色
    Page<Role> search(int page, int size);
    // 修改角色的权限
    void addPermissionToRole(Long rid, Long[] pids);
}

 编写角色Mapper

1、在管理员服务模块编写角色Mapper

public interface RoleMapper extends BaseMapper<Role> {
   // 根据id查询角色,包括权限
    Role findById(Long id);
    // 删除角色的所有权限
    void deleteRoleAllPermission(Long rid);
    // 删除用户_角色表的相关数据
    void deleteRoleAllAdmin(Long rid);
    // 给角色添加权限
    void addPermissionToRole(@Param("rid") Long rid, @Param("pid")Long pid);
}

 2、在 resources 中创建 RoleMapper 的同级包,编写映射文件 RoleMapper.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.ittxc.shopping_admin_service.mapper.RoleMapper">
    <resultMap id="roleMapper" type="com.itbaizhan.shopping_common.pojo.Role">
        <id property="rid" column="rid"></id>
        <result property="roleName" column="roleName"></result>
        <result property="roleDesc" column="roleDesc"></result>
        <collection property="permissions" column="rid" ofType="com.itbaizhan.shopping_common.pojo.Permission">
            <id property="pid" column="pid"></id>
            <result property="permissionName" column="permissionName"></result>
            <result property="url" column="url"></result>
        </collection>
    </resultMap>
    <select id="findById" parameterType="long" resultMap="roleMapper">
       SELECT *
       FROM bz_role
                 LEFT JOIN
                  bz_role_permission
                           ON bz_role.rid = bz_role_permission.rid
                 LEFT JOIN bz_permission
                           ON
                 bz_role_permission.pid = bz_permission.pid
                 WHERE bz_role.rid = #{rid}
    </select>
    <delete id="deleteRoleAllPermission" parameterType="long">
       DELETE
       FROM bz_role_permission
       WHERE rid = #{rid}
    </delete>
    
    <delete id="deleteRoleAllAdmin" parameterType="long">
       DELETE
       FROM bz_admin_role
       where rid = #{rid}
    </delete>
    <insert id="addPermissionToRole">
       INSERT INTO bz_role_permission
       VALUES (#{rid}, #{pid});
    </insert>
</mapper>

 编写角色服务实现类

管理员服务模块编写角色服务实现类

@DubboService
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
     public void add(Role role) {
        roleMapper.insert(role);
   }
    @Override
    public void update(Role role) {
        roleMapper.updateById(role);
   }
    @Override
    public void delete(Long id) {
        // 删除角色
        roleMapper.deleteById(id);
        // 删除角色的所有权限
        roleMapper.deleteRoleAllPermission(id);
        // 删除用户_角色中间表的相关数据
        roleMapper.deleteRoleAllAdmin(id);
   }
    @Override
    public Role findById(Long id) {
        return roleMapper.findById(id);
   }
    @Override
    public List<Role> findAll() {
        return roleMapper.selectList(null);
   }
    @Override
    public Page<Role> search(int page, int size) {
        return roleMapper.selectPage(new Page(page,size),null);
   }
    @Override
    public void addPermissionToRole(Long rid, Long[] pids) {
        // 删除角色的所有权限
        roleMapper.deleteRoleAllPermission(rid);
        // 给角色添加权限
        for (Long pid : pids) {
            roleMapper.addPermissionToRole(rid,pid);
       }
   }
}

编写角色控制器

后台管理Api模块编写角色控制器:

/**
* 后台角色
*/
@RestController
@RequestMapping("/role")
public class RoleController {
    @DubboReference
    private RoleService roleService;
    /**
     * 新增角色
     *
     * @param role 角色对象
     * @return 执行结果
     */
    @PostMapping("/add")
    public BaseResult add(@RequestBody Role role) {
        roleService.add(role);
        return BaseResult.ok();
   }
    /**
     * 修改角色
     *
     * @param role 角色对象
     * @return 执行结果
     */
    @PutMapping("/update")
    public BaseResult update(@RequestBody Role role) {
        roleService.update(role);
        return BaseResult.ok();
   }
    /**
     * 删除角色
     *
    * @param rid 角色id
     * @return 执行结果
     */
    @DeleteMapping("/delete")
    public BaseResult delete(Long rid) {
        roleService.delete(rid);
        return BaseResult.ok();
   }
    /**
     * 根据id查询角色
     *
     * @param rid
     * @return 查询到的角色
     */
    @GetMapping("/findById")
    public BaseResult<Role> findById(Long rid) {
        Role role = roleService.findById(rid);
        return BaseResult.ok(role);
   }
    /**
     * 分页查询角色
     *
     * @param page 页码
     * @param size 每页条数
     * @return 查询结果
     */
    @GetMapping("/search")
    public BaseResult<Page<Role>> search(int page, int size) {
        Page<Role> page1 = roleService.search(page, size);
        return BaseResult.ok(page1);
   }
    /**
     * 查询所有角色
     * @return 查询结果
     */
    @GetMapping("/findAll")
    public BaseResult<List<Role>> findAll() {
        List<Role> all = roleService.findAll();
        return BaseResult.ok(all);
   }
    /**
     * 修改角色的权限
     *
     * @param rid 角色id
     * @param pids 权限id
     * @return 执行结果
     */
    @PutMapping("/updatePermissionToRole")
    public BaseResult updatePermissionToRole(Long rid, Long[] pids) {
        roleService.addPermissionToRole(rid,pids);
        return BaseResult.ok();
   }
}

 启动服务,测试角色控制器方法

编写权限服务接口

接下来我们编写权限相关的CRUD方法,首先在通用模块编写权限服务接口:

public interface PermissionService {
    // 新增权限
    void add(Permission permission);
    // 修改权限
    void update(Permission permission);
    // 删除权限
    void delete(Long id);
    // 根据id查询权限
    Permission findById(Long id);
    // 分页查询权限
    Page<Permission> search(int page, int size);
    // 查询所有权限
    List<Permission> findAll();
}

编写权限Mapper

1、在管理员服务模块编写权限Mapper

public interface PermissionMapper extends BaseMapper<Permission> {
    // 删除角色_权限表中的相关数据
    void deletePermissionAllRole(Long pid)
}

 2、编写权限Mapper映射文件

<?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.ittxc.shopping_admin_service.mapper.PermissionMapper">
    
    <delete id="deletePermissionAllRole" parameterType="long">
       DELETE
       FROM bz_role_permission
       WHERE pid = #{pid}
    </delete>
</mapper>

编写权限服务实现类

管理员服务模块编写权限服务实现类 

@DubboService
public class PermissionServiceImpl implements PermissionService {
    @Autowired
    private PermissionMapper permissionMapper;
    @Override
    public void add(Permission permission) {
        permissionMapper.insert(permission);
   }
    @Override
    public void update(Permission permission) {
        permissionMapper.updateById(permission);
   }
    @Override
    public void delete(Long id) {
        // 删除权限
        permissionMapper.deleteById(id);
        // 删除角色_权限表中的相关数据
        permissionMapper.deletePermissionAllRole(id);
   }
    @Override
    public Permission findById(Long id) {
        return permissionMapper.selectById(id);
   }
    @Override
    public Page<Permission> search(int page, int size) {
        return permissionMapper.selectPage(new Page(page,size),null);
   }
    @Override
    public List<Permission> findAll() {
        return permissionMapper.selectList(null);
   }
}

 编写权限控制器

后台管理Api模块编写权限控制器:

/**
* 后台权限
*/
@RestController
@RequestMapping("/permission")
public class PermissionController {
    @DubboReference
    private PermissionService permissionService;
    /**
     * 新增权限
     * @param permission 权限对象
     * @return 执行结果
     */
    @PostMapping("/add")
    public BaseResult add(@RequestBody Permission permission){
        permissionService.add(permission);
        return BaseResult.ok();
   }
    /**
     * 修改权限
     * @param permission 权限对象
     * @return 执行结果
     */
    @PutMapping("/update")
    public BaseResult update(@RequestBody Permission permission){
        permissionService.update(permission);
        return BaseResult.ok();
   }
    /**
     * 删除权限
     * @param pid 权限id
     * @return 执行结果
     */
    @DeleteMapping("/delete")
    public BaseResult delete(Long pid){
        permissionService.delete(pid);
        return BaseResult.ok();
   }
    /**
     * 根据id查询权限
     * @param pid 权限id
     * @return 查询结果
     */
    @GetMapping("/findById")
    public BaseResult<Permission> findById(Long pid){
        Permission permission = permissionService.findById(pid);
        return BaseResult.ok(permission);
   }
    /**
     * 分页查询权限
     * @param page 页面
     * @param size 每页条数
     * @return 查询结果
     */
    @GetMapping("/search")
    public BaseResult<Page<Permission>> search(int page,int size){
        Page<Permission> permissionPage = permissionService.search(page, size);
        return BaseResult.ok(permissionPage);
   }

    /**
     * 查询所有权限
     * @return 所有权限
     */
    @GetMapping("/findAll")
    public BaseResult<List<Permission>> findAll(){
        List<Permission> all = permissionService.findAll();
        return BaseResult.ok(all);
   }
}

 启动服务,测试权限控制器方法

编写Security处理器

接下来我们使用Spring Security编写管理员认证和授权功能。 Spring Security在访问接口时进行认证和授权,所以Spring Security的相关代码编写在管理员API模块。 之前使用Spring Security时,登录后会配置跳转页面。但百战商城 是前后端分离项目,所有认证和授权的结果,只是返回json字符串 让前端去处理。所以我们要创建 认证成功处理器 、 认证失败处理器 、 未登录处理 器 、 权限不足处理器 、 登出成功处理器 处理不同的结果,Spring Security通过 实现接口编写结果处理器。

1、在管理员API模块引入Spring Security的依赖 

<!-- spring security -->
<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2、编写认证成功、认证失败处理器

// 登录成功处理器
public class MyLoginSuccessHandler
implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException, ServletException {
       response.setContentType("text/json;charset=utf-8");
        BaseResult result = new BaseResult(200, "登录成功", null);
        response.getWriter().write(JSON.toJSONString(result));
   }
}
// 登录失败处理器
public class MyLoginFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
       response.setContentType("text/json;charset=utf-8");
        BaseResult result = new BaseResult(402, "用户名或密码错误", null);
        response.getWriter().write(JSON.toJSONString(result));
   }
}

3、编写未登录处理器

// 未登录处理器
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("text/json;charset=utf-8");
        BaseResult result = new BaseResult(401, "用户名未登录", null);
        response.getWriter().write(JSON.toJSONString(result));
   }
}

4、编写权限不足处理器

// 权限不足处理器
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setContentType("text/json;charset=utf-8");
        BaseResult result = new BaseResult(403, "权限不足", null);
        response.getWriter().write(JSON.toJSONString(result));
   }
}

5、编写登出成功处理器

// 登出成功处理器
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException, ServletException {
        response.setContentType("text/json;charset=utf-8");
        BaseResult result = new BaseResult(200, "注销成功", null);
        response.getWriter().write(JSON.toJSONString(result));
   }
}

编写Security配置类

后台管理API模块编写Spring Security配置类

// Security配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // Spring Security配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义表单登录
        http.formLogin()
               .usernameParameter("username") // 用户名项
               .passwordParameter("password") // 密码项
               .loginProcessingUrl("/admin/login") // 登录提交路径
               .successHandler(new MyLoginSuccessHandler()) // 登录成功处理器
               .failureHandler(new MyLoginFailureHandler()); // 登录失败处理器
        // 权限拦截配置
        http.authorizeRequests()
               .antMatchers("/login").permitAll() // 登录页不需要认证
               .antMatchers("/admin/login").permitAll() //登录请求不需要认证
               .anyRequest().authenticated(); // 其余请求都需要认证
        // 退出登录配置
        http.logout()
               .logoutUrl("/admin/logout")// 注销的路径
               .logoutSuccessHandler(new MyLogoutSuccessHandler()) // 登出成功处理器
               .clearAuthentication(true)// 清除认证数据
               .invalidateHttpSession(true);  // 清除session
        // 异常处理
        http.exceptionHandling()
               .authenticationEntryPoint(new MyAuthenticationEntryPoint()) // 未登录处理器
               .accessDeniedHandler(new MyAccessDeniedHandler()); // 权限不足处理器
        // 关闭csrf防护
        http.csrf().disable();
        // 开启跨域访问
        http.cors();
   }
    @Bean
    public PasswordEncoder passwordEncoder()
     {
        return new BCryptPasswordEncoder();
     }
}

编写认证授权相关的服务方法

1、在管理员服务接口添加 根据用户名查询管理员根据用户名查询权限 方法

// 根据名字查询管理员
Admin findByAdminName(String username);
// 根据名字查询管理员所有权限
List<Permission> findAllPermission(String username);

 2、在管理员服务模块编写管理员Mapper

// 根据管理员名查询权限
List<Permission> findAllPermission(String username);

编写AdminMapper.xml

<select id="findAllPermission" resultType="com.itbaizhan.shopping_pojo.pojo.Permission" parameterType="string">
   SELECT
       DISTINCT bz_permission.*
   FROM
       bz_admin
           LEFT JOIN bz_admin_role
                     ON bz_admin.aid =
           bz_admin_role.aid
           LEFT JOIN bz_role
                     ON bz_admin_role.rid = bz_role.rid
           LEFT JOIN bz_role_permission
                     ON bz_role.rid = bz_role_permission.rid
           LEFT JOIN bz_permission
                     ON
           bz_role_permission.pid = bz_permission.pid
           WHERE bz_admin.username = #{username}
</select>

3、在管理员服务模块编写管理员服务接口实现类

@Override
public Admin findByAdminName(String username) {
    QueryWrapper<Admin> wrapper = new QueryWrapper();
    wrapper.eq("username", username);
    Admin admin = adminMapper.selectOne(wrapper);
    return admin;
}
@Override
public List<Permission> findAllPermission(String username) {
    return adminMapper.findAllPermission(username);
}

编写认证授权逻辑

后台管理API模块编写认证和授权逻辑

@Service
public class MyUserDetailService implements
UserDetailsService {
    @DubboReference
    private AdminService adminService;
    @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1.认证
        Admin admin = adminService.findByAdminName(username);
        if(admin == null){
            throw new UsernameNotFoundException("用户不存在");
       }
        
        // 2.授权
        List<Permission> permissions = adminService.findAllPermission(username);
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        for (Permission permission : permissions) {
            grantedAuthorities.add(new SimpleGrantedAuthority(permission.getUrl()));
       }
        // 3.封装为UserDetails对象
        UserDetails userDetails = User.withUsername(admin.getUsername())
               .password(admin.getPassword())
               .authorities(grantedAuthorities)
               .build();
        // 4.返回封装好的UserDetails对象
        return userDetails;
   }
}

编写接口鉴权配置

我们要对接口进行鉴权配置,即用户拥有权限才能访问接口。

1、开启鉴权配置注解

// Security配置类
@Configuration
// 开启鉴权配置注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
}

2、在需要鉴权的接口上方添加鉴权注解

/**
  * 分页查询管理员
  * @param page 页码
  * @param size 每天条数
  * @return 查询结果
  */
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('/admin/all')")
public BaseResult<Page<Admin>> search(int page, int size){
Page<Admin> adminPage = adminService.search(page, size);
    return BaseResult.ok(adminPage);
}
/**
  * 分页查询角色
  * @param page 页码
  * @param size 每页条数
  * @return 查询结果
  */
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('/role/all')")
public BaseResult<Page<Role>> search(int page, int size){
    Page<Role> rolePage = roleService.search(page, size);
    return BaseResult.ok(rolePage);
}

3、使用不同权限的用户登录,查看他们是否能访问这些接口

测试时,当用户权限不足时,系统会抛出500异常,这是由于全 局异常处理器先处理了异常,使得异常没有交由 AccessDeniedHandler 。此时我们需要在管理员API模块添加异常处理 器,当捕获到 AccessDeniedException 异常时,直接抛出,此时异常就 会交给 AccessDeniedHandler 处理。

// 统一异常处理器
@RestControllerAdvice
public class AccessDeniedExceptionHandler
{
  // 处理权限不足异常,捕获到异常后再次抛出,交给 AccessDeniedHandler处理
  @ExceptionHandler(AccessDeniedException.class)
  public void defaultExceptionHandler(AccessDeniedException e) throws AccessDeniedException{
      throw e;
 }
}

 修改新增/修改管理员方法

接下来修改新增用户和修改用户方法,对密码进行加密:

@RestController
@RequestMapping("/admin")
public class AdminController {
    @Autowired
    private PasswordEncoder encoder;
    /**
     * 新增管理员
     * @param admin 管理员对象
     * @return 执行结果
     */
    @PostMapping("/add")
      public BaseResult add(@RequestBody Admin admin) {
        String password = admin.getPassword();
        password = encoder.encode(password);
        admin.setPassword(password);
        adminService.add(admin);
        return BaseResult.ok();
   }
    /**
     * 修改管理员
     * @param admin 管理员对象
     * @return 执行结果
     */
    @PutMapping("/update")
    public BaseResult update(@RequestBody Admin admin) {
        String password = admin.getPassword();
        if (StringUtils.hasText(password)){
            // 密码不为空加密
            password = encoder.encode(password);
            admin.setPassword(password);
       }
        adminService.update(admin);
        return BaseResult.ok();
   }
}
@DubboService
public class AdminServiceImpl implements
AdminService {
    @Override
    public void update(Admin admin) {
        // 如果前端传来空密码,则密码还是原来的密码
        if(!StringUtils.hasText(admin.getPassword())){
            // 查询原来的密码
            String password = adminMapper.selectById(admin.getAid()).getPassword();
            admin.setPassword(password);
       }
        adminMapper.updateById(admin);
   }
}

编写获取登录管理员名方法

/**
* 获取登录管理员名
*
* @return 管理员名
*/
@GetMapping("/getUsername")
public BaseResult<String> getUsername() {
    // 1.获取会话对象
    SecurityContext context = SecurityContextHolder.getContext();
    // 2.获取认证对象
    Authentication authentication = context.getAuthentication();
    // 3.获取登录用户信息
    UserDetails userDetails = (UserDetails)authentication.getPrincipal();
    String username = userDetails.getUsername();
    return BaseResult.ok(username);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/346203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用nvm管理node

nvm介紹 node的版本管理器&#xff0c;可以方便地安装&切换不同版本的node 我们在工作中&#xff0c;可以会有老版本的node的项目需要维护&#xff0c;也可能有新版本的node的项目需要开发&#xff0c;如果只有一个node版本的话将会很麻烦&#xff0c;nvm可以解决我们的难点…

node 拉取github开源漏洞

我们可以通过github的open api 来拉取一些信息。这里主要是拉取 github 开源漏洞中的漏洞信息 Github Explorer github Explorer 是一个在线工具&#xff0c;登录之后&#xff0c;我们可以在左侧输入GraphQL 查询语句&#xff0c;之后就可以查询相关的信息。例如&#xff1a;…

B树和B+树,红黑树作为索引的区别

索引是一种数据结构&#xff0c;帮助我们在mysql表中更高效获取数据的数据结构 常用作为索引的数据结构&#xff1a;二叉树&#xff0c;红黑树&#xff0c;Hash表&#xff0c;B树&#xff0c;B树 下面的数据表中有两个字段&#xff0c;第一个字段是col1&#xff0c;第二个字段…

如何在Qt中设置背景图片,且不覆盖其它控件

正常情况&#xff0c;我们直接通过在样式表里设置背景图片会出现背景图片覆盖其它控件的情况&#xff0c;比如下面操作&#xff1a; 首先右击空白处&#xff0c;点击改变样式表。 然后选择background-image 然后点击铅笔图标 之后我们要先添加前缀&#xff0c;也就是我们…

使用 Three.js 后处理的粗略铅笔画效果

本文使用Three.js的后处理创建粗略的铅笔画效果。我们将完成创建自定义后处理渲染通道、在 WebGL中实现边缘检测、将法线缓冲区重新渲染到渲染目标以及使用生成和导入的纹理调整最终结果的步骤。翻译自Codrops&#xff0c;有改动。 Three.js 中的后处理 Three.js中的后处理是一…

1.9 实践项目——爬取学生信息

1. 项目简介设计一个 Web 服务器 server.py&#xff0c;它读取 students.txt 文件中的学生数据&#xff0c;以表格的形式呈现在网页上&#xff0c;其中 students.txt 的格式如下&#xff1a;No,Name,Gender,Age1001,张三,男,201002,李四,女,191003,王五,男,21设计一个客户端的爬…

【Junit5】就这篇,带你从入门到进阶

目录 前言 1.前置工作 2、注解 2、断言&#xff08;Assertions类&#xff09; 2.1、断言 匹配/不匹配 2.2、断言结果 为真/为假 2.3、断言结果 为空/不为空 3、用例的执行顺序 3.1、用例执行顺序是怎样的&#xff1f; 3.2、通过order注解来排序 4、参数化 4.1、单…

Firefox 110, Chrome 110, Chromium 110 官网离线下载 (macOS, Linux, Windows)

Mozilla Firefox, Google Chrome, Chromium, Apple Safari 请访问原文链接&#xff1a;https://sysin.org/blog/chrome-firefox-download/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 天下只剩三种&#xff08;主流&am…

feign技巧 - form方式传值

feign技巧 - form方式传值。 0. 文章目录1. 前言2. 调用样例3. 原理解析3.1 feign端序列化参数3.2 SpringMVC服务端解析参数3.3 补充 - 继承关系不会被传递的原因3.4 补充 - 不能使用GET。4. 总结1. 前言 直接正题。 如何使用feign进行fom表单方式的请求调用&#xff0c;以及其…

leaflet 上传KMZ文件,并在map上显示(062)

第062个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中本地上传包kmz文件,解析并在地图上显示图形。在制作本示例的过程中,还有点缺憾,就是kmz中的图片文件没有在jszip中处理好,只能先解压缩后,将图片文件放到public/文件加下,暂时留一个遗憾点,以后再做…

又发现一个ChatGPT体验站,辅助写代码真方便

♥️ 作者&#xff1a;Hann Yang ♥️ 主页&#xff1a;CSDN主页 ♥️ 2022博客之星Top58&#xff0c;原力榜Top10/作者周榜Top13 ♥️ “抢走你工作的不会是 AI &#xff0c;而是先掌握 AI 能力的人” ChatGPT 美国OpenAI研发的聊天机器人程序&#xff0c;于2022年11月30日发…

【刷题笔记】--两数之和Ⅳ,从二叉树中找出两数之和

法一&#xff1a;深度搜索中序遍历双指针 思路&#xff1a;通过中序遍历二叉树得到一个递增的数列&#xff0c;再在这个递增的二叉树中找到这两数。 主要学到双指针这个方法。 对于一般数列&#xff0c;我们要找到两数满足其之和等于目标数&#xff0c;我们一般会进行暴力&a…

C++请求SpringBoot的接口问题记录

问题描述最近忙一个小东西&#xff0c;遇到一个很有意思的问题&#xff0c;记录一下。 需求非常简单&#xff0c;就是java侧提供一个接口给C侧调用。 接口按照业务规范提供出来了&#xff0c;在postman中请求一下&#xff0c;出入参都正常。 关于这个接口请求方式为postJson方式…

C++:提高篇: 栈-寄存器和函数状态:栈指针帧指针详解

栈指针和帧指针前言1、EBP和ESP详解2、push &#xff0c;leave &#xff0c;call汇编指令分析3、下面用一个图总结前言 &#x1f697;&#x1f697;&#x1f697;&#xff1a;在刚接触 ESP和EBP概念时&#xff0c;我一直认为&#xff1a;ESP指向栈顶指针&#xff0c;EBP指向栈…

为什么说百度下个月推出文心一言会被ChatGPT完全碾压

作者&#xff0c;姚远&#xff1a; Oracle ACE&#xff08;Oracle和MySQL数据库方向&#xff09;华为云MVP 《MySQL 8.0运维与优化》的作者中国唯一一位Oracle高可用大师拥有包括 Oracle 10g和12c OCM在内的20数据库相关认证。曾任IBM公司数据库部门经理现在一家第三方公司任首…

操作系统——2.操作系统的特征

这篇文章&#xff0c;我们来讲一讲操作系统的特征 目录 1.概述 2.并发 2.1并发概念 2.1.1操作系统的并发性 3.共享 3.1共享的概念 3.2共享的方式 4.并发和共享的关系 5.虚拟 5.1虚拟的概念 5.2虚拟小结 6.异步 6.1异步概念 7.小结 1.概述 上一篇文章&#xff0c;我们…

实时数据仓库

1 为什么选择kafka? ① 实时写入&#xff0c;实时读取 ② 消息队列适合&#xff0c;其他数据库受不了 2 ods层 1&#xff09;存储原始数据 埋点的行为数据 (topic &#xff1a;ods_base_log) 业务数据 (topic &#xff1a;ods_base_db) 2&#xff09;业务数据的有序性&#x…

论文阅读 - Early Detection of Fake News by Utilizing the Credibility of News

论文链接&#xff1a;https://arxiv.org/pdf/2012.04233.pdf 目录 摘要 1 简介 2 相关工作 2.1 基于特征的方法 2.2 深度学习方法 3 问题表述 4 拟议的框架 4.2 用户可信度预测 4.3 虚假新闻分类 4.3.1 新闻内容表示 4.3.2 融合注意力单元 5 实验 5.1 数…

工厂模式--设计模式

分类&#xff1a; 1、简单工厂&#xff1a;可根据自变量的不同返回不同类的实例 应用&#xff1a;将类名和类的全路径放入到配置文件&#xff0c;通过文件流将内容读取放入到map集合中保存&#xff0c;通过反射读取类全路径读取到该类&#xff0c;然后调用类方法。 详细设计&…

山东大学2022算法期末

接力&#xff1a;山东大学2021算法期末 2022 SDU算法导论期末考试 2020 计科 计算题 三道 35’ (1) 画BFS树 (2) 做DFS说明各种边的分类使用floyd或者矩阵乘法求全源最短路&#xff0c;求最短路矩阵以及前驱矩阵&#xff08;3个点&#xff0c;比较友好&#xff0c;应该没有…