springboot+shiro+jwt 兼容session和token

news2024/7/6 19:55:50

最近和别的软件集成项目,需要提供给别人接口来进行数据传输,发现给他token后并不能访问我的接口,拿postman试了下还真是不行。检查代码发现项目的shiro配置是通过session会话来校验信息的 ,我之前一直是前后端自己写,用浏览器来调试的程序所以没发现这个问题。
浏览器请求头的cookie带着JESSIONID是可以正常访问接口的
在这里插入图片描述

那要和别的项目集成,他那边又不是通过浏览器,咋办呢,我这边改造吧,兼容token和session不就行了,下面直接贴改造后的完整代码。

pom加依赖

		<dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>2.4.2.1-RELEASE</version>
        </dependency>
             <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>

1.JwtToken重写token类型

package com.mes.common.token;

import com.mes.module.user.dto.SysUserDto;
import lombok.Data;
import org.apache.shiro.authc.HostAuthenticationToken;
import org.apache.shiro.authc.RememberMeAuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;


@Data
public class JwtToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
    private String token;
    private char[] password;
    private boolean rememberMe = false;
    private String host;

    public JwtToken(String token){
        this.token = token;
    }


    @Override
    public String getHost() {
        return null;
    }

    @Override
    public boolean isRememberMe() {
        return false;
    }

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }
}

2.自定义过滤器 JwtFilter

package com.mes.common.shiro;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.interfaces.Claim;
import com.mes.common.token.JwtToken;
import com.mes.common.utils.JwtUtils;
import com.mes.common.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

/**
 * @Description 自定义过滤器
 * @Date 2021/8/18
 **/
public class JwtFilter extends AuthenticatingFilter {

    private static final Logger log = LoggerFactory.getLogger(JwtFilter.class);
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader("token");
        if (token == null){
            return null;
        }
        return new JwtToken(token);
    }


    /**
     * 拦截校验  没有登录的情况下会走此方法
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String token = request.getHeader("token");

        response.setContentType("application/json;charset=utf-8");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "GET,PUT,DELETE,UPDATE,OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));

        Subject subject = getSubject(servletRequest,servletResponse);

        if (!subject.isAuthenticated()){
            // 未登录
            PrintWriter writer = response.getWriter();
            writer.print(JSON.toJSONString(new Result<>().setCode(402).setMsg("请先登录")));
            return false;
        }

        if (StringUtils.isEmpty(token)){
            PrintWriter writer = response.getWriter();
            writer.print(JSON.toJSONString(new Result<>().setCode(402).setMsg("请先登录")));
            return false;
        }else {
            // 校验jwt
            try {
                Map<String, Claim> claimMap = JwtUtils.verifyToken(token);
            } catch (Exception e) {
                e.printStackTrace();
                PrintWriter writer = response.getWriter();
                writer.write(JSON.toJSONString(new Result<>().setCode(402).setMsg("登录失效,请重新登录")));
                return false;
            }
            return executeLogin(servletRequest, servletResponse);
        }
    }
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {

        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        Throwable throwable = e.getCause() == null ? e : e.getCause();

        Result result = new Result().err().setMsg(e.getMessage());
        String json = JSON.toJSONString(result);

        try {
            httpServletResponse.getWriter().print(json);
        } catch (IOException ioException) {

        }
        return false;
    }

    /**
     * 跨域支持
     * @param servletRequest
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean preHandle(ServletRequest servletRequest, ServletResponse response) throws Exception {
        HttpServletRequest httpRequest = WebUtils.toHttp(servletRequest);
        HttpServletResponse httpResponse = WebUtils.toHttp(response);
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-control-Allow-Origin", httpRequest.getHeader("Origin"));
            httpResponse.setHeader("Access-Control-Allow-Methods", "GET,PUT,DELETE,UPDATE,OPTIONS");
            httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));

            System.out.println(httpRequest.getHeader("Origin"));
            System.out.println(httpRequest.getMethod());
            System.out.println(httpRequest.getHeader("Access-Control-Request-Headers"));
            httpResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader("token");
        if (token != null) {
            try {
//                Map<String, Claim> claimMap = JwtUtils.verifyToken(token);
//                String authToken = claimMap.get("token").asString();
                JwtToken jwtToken = new JwtToken(token);
                Subject subject = SecurityUtils.getSubject();
                subject.login(jwtToken);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                log.error("token失效,请重新登录");
               response.getWriter().print(JSON.toJSONString(new Result<>().setCode(402).setMsg("token失效,请重新登录")));
            }
        }
        return false;
    }

/*    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpRequest = WebUtils.toHttp(request);
        HttpServletResponse httpResponse = WebUtils.toHttp(response);
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-control-Allow-Origin", httpRequest.getHeader("Origin"));
            httpResponse.setHeader("Access-Control-Allow-Methods", "GET,PUT,DELETE,UPDATE,OPTIONS");
            httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));

            System.out.println(httpRequest.getHeader("Origin"));
            System.out.println(httpRequest.getMethod());
            System.out.println(httpRequest.getHeader("Access-Control-Request-Headers"));
            httpResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }*/

}

3.配置过滤器 ShiroFilterRegisterConfig

package com.mes.common.config;

import com.mes.common.shiro.JwtFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description TODO
 * @Date 2021/8/19
 **/
@Configuration
public class ShiroFilterRegisterConfig {
    @Bean
    public FilterRegistrationBean shiroLoginFilteRegistration(JwtFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }
}

4. shiroConfig

package com.mes.common.config;

import com.baomidou.mybatisplus.extension.api.R;
import com.mes.common.constant.ExpTime;
import com.mes.common.realm.MyRealm;
import com.mes.common.shiro.JwtFilter;
import com.mes.common.shiro.MyCredentialsMatcher;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**

  • @Description shiro配置
  • @Date 2021/8/18
    **/
    @Configuration
    public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;
    @Autowired
    private MyCredentialsMatcher myCredentialsMatcher;
    @Value(“ s p r i n g . r e d i s . h o s t " ) p r i v a t e S t r i n g r e d i s H o s t ; @ V a l u e ( " {spring.redis.host}") private String redisHost; @Value(" spring.redis.host")privateStringredisHost;@Value("{spring.redis.port}”)
    private Integer redisPort;
    @Value(“${spring.redis.timeout}”)
    private Integer redisTimeout;

// @Bean
// public DefaultWebSessionManager sessionManager(@Value(“${globalSessionTimeout:3600}”) long globalSessionTimeout, RedisManager c){
// DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// sessionManager.setSessionValidationSchedulerEnabled(true);
// sessionManager.setSessionIdUrlRewritingEnabled(false);
// sessionManager.setSessionValidationInterval(globalSessionTimeout * 1000);
// sessionManager.setGlobalSessionTimeout(globalSessionTimeout * 1000);
// sessionManager.setSessionDAO(redisSessionDAO©);
// return sessionManager;
// }
// @ConfigurationProperties(prefix=“spring.redis”)
// @Bean
// public RedisManager redisManager() {
// return new RedisManager();
// }
// @Bean
// public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {
// RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
// redisSessionDAO.setRedisManager(redisManager);
// return redisSessionDAO;
// }

// @Bean
// public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
//
// DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
// defaultAdvisorAutoProxyCreator.setUsePrefix(true);
//
// return defaultAdvisorAutoProxyCreator;
// }

@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(SessionManager sessionManager, RedisCacheManager redisCacheManager){
    DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    myRealm.setCredentialsMatcher(myCredentialsMatcher);
    defaultWebSecurityManager.setRealm(myRealm);

// defaultWebSecurityManager.setSessionManager(sessionManager);
defaultWebSecurityManager.setCacheManager(redisCacheManager);
return defaultWebSecurityManager;
}

@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager,JwtFilter jwtFilter){
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

// JwtFilter jwtFilter = new JwtFilter();
Map<String, Filter> filterMap = new HashMap<>();
filterMap.put(“jwt”,jwtFilter);
shiroFilterFactoryBean.setFilters(filterMap);
Map<String,String> map = new LinkedHashMap<>();
map.put(“/sys/user/login”,“anon”);
map.put(“/swagger-ui.html**”, “anon”);
map.put(“/v2/api-docs”, “anon”);
map.put(“/swagger-resources/“, “anon”);
map.put(”/webjars/
”, “anon”);
map.put(“/img/“,“anon”);
map.put(”/fastdfs/
”,“anon”);
map.put(“/**”,“jwt”); //取消就不会拦截
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
// shiroFilterFactoryBean.setLoginUrl(“http://192.168.18.17:3000”);
return shiroFilterFactoryBean;
}

@Bean
public JwtFilter getJwtFilter(){
    return new JwtFilter();
}



/**
 * 配置shiro redisManager
 * 使用的是shiro-redis开源插件
 * @return
 */
@Bean
public RedisManager redisManager() {
    RedisManager redisManager = new RedisManager();
    redisManager.setHost(redisHost);
    redisManager.setPort(redisPort);
    redisManager.setExpire(Math.toIntExact(ExpTime.expTime));// 配置缓存过期时间
    redisManager.setTimeout(redisTimeout);
    return redisManager;
}
@Bean
public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {

// RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager);
return redisSessionDAO;
}
/**
* shiro session的管理
*/
@Bean
public DefaultWebSessionManager redisSessionManager(RedisSessionDAO redisSessionDAO) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO);
return sessionManager;
}
@Bean
public RedisCacheManager redisCacheManager(RedisManager redisManager) {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager);
return redisCacheManager;
}

// @Bean
// public FilterRegistrationBean shiroLoginFilteRegistration(JwtFilter filter) {
// FilterRegistrationBean registration = new FilterRegistrationBean(filter);
// registration.setEnabled(false);
// return registration;
// }

}

在这里插入代码片

5.自定义认证逻辑 MyRealm

package com.mes.common.realm;

import com.auth0.jwt.interfaces.Claim;
import com.mes.common.token.JwtToken;
import com.mes.common.utils.JwtUtils;
import com.mes.module.user.dto.SysUserDto;
import com.mes.module.user.service.SysUserService;
import lombok.SneakyThrows;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**

  • @Description 授权

  • @Date 2021/8/18
    **/
    @Component
    public class MyRealm extends AuthorizingRealm {
    @Autowired
    private SysUserService sysUserService;

    @Override
    public boolean supports(AuthenticationToken token) {
    return token instanceof JwtToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    String username = (String) principalCollection.iterator().next();
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    return info;
    }

    @SneakyThrows
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    JwtToken jwtToken = (JwtToken) authenticationToken;
    String token = (String) jwtToken.getPrincipal();
    Map<String, Claim> claimMap = JwtUtils.verifyToken(token);
    String username = claimMap.get(“name”).asString();
    Map<String,Object> params = new HashMap<>();
    params.put(“username”, username);
    SysUserDto userDto = sysUserService.getOne(params);
    if (userDto == null){
    return null;
    }

// return new SimpleAuthenticationInfo(userDto,userDto.getPassword(),getName());
return new SimpleAuthenticationInfo(userDto,jwtToken,getName());
}
}

6.密码验证器

package com.mes.common.shiro;

import com.mes.common.token.JwtToken;
import com.mes.common.utils.CommonsUtils;
import com.mes.module.user.dto.SysUserDto;
import com.mes.module.user.service.SysUserService;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description 密码验证器
 * @Date 2021/8/18
 **/
@Component
public class MyCredentialsMatcher extends SimpleCredentialsMatcher {
    @Autowired
    private SysUserService sysUserService;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

        JwtToken jwtToken = (JwtToken) token;
        if (jwtToken.getPassword() == null){
            return true;
        }
        String inPassword = new String(jwtToken.getPassword());
        SysUserDto dto = (SysUserDto) info.getPrincipals();
        String username = dto.getUsername();
        String dbPassword = String.valueOf(info.getCredentials());
        Map<String,Object> params = new HashMap<>();
        params.put("username",username);
        SysUserDto dbUser = sysUserService.getOne(params);
        String salt = dbUser.getSalt();
        if (CommonsUtils.encryptPassword(inPassword,salt).equals(dbPassword)){
            return true;
        }else {
            return false;
        }


    }
}

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

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

相关文章

总结了几类Midjourney制作网站风格设计的关键词和方法

第一种&#xff1a;根据简单的图生成你想要的设计风格Demo 我们拿MJ的一款网站风格分析 类似你只有一款产品图或者是风格框架图&#xff0c;JPG或者PNG透明格式都OK&#xff0c;来生成网站首页设计风格。 1&#xff1a;你先上传产品图到MJ 2&#xff1a;打开命令行&#xff…

Linux Radix tree简介

文章目录 前言一、Radix tree简介二、Operations2.1 Lookup2.2 Insertion2.3 Deletion 三、Linux内核API3.1 初始化3.2 radix_tree_insert/delete3.3 radix_tree_preload3.4 radix_tree_lookup3.5 radix_tree_tag_set3.6 radix_tree_tagged 四、address_space4.1 简介4.2 相应数…

浅谈配置元件之HTTP请求默认值

浅谈配置元件之HTTP请求默认值 在进行HTTP请求的测试计划设计时&#xff0c;"HTTP请求默认值"配置元件扮演着极其重要的角色&#xff0c;它能够简化测试计划的设置&#xff0c;提高测试效率。本问将详细介绍如何使用JMeter中的“HTTP请求默认值”配置元件。 HTTP请求…

每日一题——Python实现PAT甲级1116 Come on! Let‘s C(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码点评 时间复杂度分析 空间复杂度分析 总结 我要更强 优化思路 优化…

四川古力未来科技抖音小店可靠购物新体验

在当下数字化浪潮席卷的时代&#xff0c;抖音小店作为电商领域的新兴力量&#xff0c;正以其独特的魅力吸引着越来越多的消费者。而四川古力未来科技抖音小店&#xff0c;作为其中的佼佼者&#xff0c;其可靠性与否自然成为了广大消费者关注的焦点。本文将从多个角度对四川古力…

Pytorch环境深度学习环境

Pytorch环境深度学习环境 1、安装minicoda 下载地址&#xff1a;Miniconda — miniconda documentation 设置环境变量&#xff1a; 安装路径\Miniconda3 安装路径\Miniconda3\Scripts安装路径\Miniconda3\Library\bin 测试&#xff1a;打开cmd&#xff0c;输入conda测试指令…

Java的核心类库

引言 在Java编程中&#xff0c;熟练掌握常用类与对象操作是开发的基础。Java的核心类库提供了丰富的功能&#xff0c;可以帮助开发者高效地处理各种编程任务。本文将详细介绍Java字符串操作、集合框架、日期与时间处理等内容&#xff0c;并通过图表和表格进行总结与示范。 字符…

神经网络 torch.nn---nn.RNN()

torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) RNN — PyTorch 2.3 documentation torch.nn---nn.RNN() nn.RNN(input_sizeinput_x,hidden_sizehidden_num,num_layers1,nonlinearitytanh, #默认tanhbiasTrue, #默认是Truebatch_firstFalse,dropout0,bidirection…

遥控器无法点击AOSP Settings 的管理存储按钮 MANAGE STORAGE

前言 这里是遇到了MANAGE STORAGE的按钮使用遥控器移动的时候无法聚焦到这个按钮&#xff0c;自然也就无法点击。它只能聚焦到这一整个整体&#xff0c;因此我就设置当点击到这一整个整体时&#xff0c;就相应MANAGE STORAGE按钮的点击事件。 图片 代码 packages/apps/Setti…

极限存在的条件

极限存在的条件 在左极限与又极限相关的内容中我们知道极限&#xff08;也叫双侧极限&#xff09;存在的充分必要条件是左右极限都存在且相等&#xff0c;否则极限不存在。所以这里要来详细的探讨一下在什么情况下函数会不存在极限。 1. 函数 f ( x ) 1 x f(x)\frac{1}{x} …

知识分享|个人查询大数据信用有哪些好处?

在当今数字化时代&#xff0c;个人信用评估已经成为金融、购物、租房等各个方面的关键因素。大数据技术的兴起为个人信用查询带来了新的可能性和好处。下面将探讨个人查询大数据信用的益处。 首先&#xff0c;个人查询大数据信用可以全面了解自己的信用状况 通过查询大数据信用…

46.Python-web框架-Django - 多语言配置

目录 1.Django 多语言基础知识 1.1什么是Django国际化和本地化&#xff1f; 1.2Django LANGUAGE_CODE 1.3关于languages 1.4RequestContext对象针对翻译的变量 2.windows系统下的依赖 3.django多语言配置 3.1settings.py配置 引用gettext_lazy 配置多语言中间件&#x…

白酒:茅台镇白酒的品鉴课程与文化学习

茅台镇&#xff0c;这个位于中国贵州省的美丽小镇&#xff0c;以其与众不同的自然环境和杰出的酿酒工艺&#xff0c;成为了世界著名的白酒产区。作为茅台镇的杰出代表&#xff0c;云仓酒庄豪迈白酒不仅在国内享有盛誉&#xff0c;在国际市场上也备受瞩目。为了更好地推广中国白…

产品经理研读:Agent的九种设计模式(图解+代码)

引言 上周五我在一个特工宇宙的社群里做了一次分享&#xff0c;题目是《从 YC 项目看 AI 趋势以及 AI agent 开发工具类产品该如何设计》&#xff0c;收到了大家不错的反馈&#xff0c;不过回看视频后还是发现不少可以提升的地方&#xff0c;感兴趣的朋友公众号回复“分享”获…

【CMake】CMake从入门到实战系列(十六)—— CMake中设置交叉编译

文章目录 一、前言二、切换编译器的方法1、修改系统环境变量来指定编译器2、CMake命令行中指定编译器3、CMakeLists.txt中指定编译器4、示例 一、前言 CMake是一个强大的跨平台的编译工具&#xff0c;实际嵌入式开发过程中&#xff0c;经常需要使用到交叉编译。在Ubuntu环境中…

linux中: IDEA 由于JVM 设置内存过小,导致打开项目闪退问题

1. 找到idea安装目录 由于无法打开idea&#xff0c;只能找到idea安装目录 在linux(debian/ubuntu)中idea的插件默认安装位置和配置文件在哪里? 默认路径&#xff1a; /home/当前用户名/.config/JetBrains/IntelliJIdea2020.具体版本号/options2. 找到jvm配置文件 IDEA安装…

Visual Studio编译fatal error C1001: 编译器中发生内部错误

项目本来是能正常编译的&#xff0c;但是突然出现“fatal error C1001: 编译器中发生内部错误。” 2> (编译器文件“f:\dd\vctools\compiler\utc\src\p2\main.c”&#xff0c;第 255 行) 2> 要解决此问题&#xff0c;请尝试简化或更改上面所列位置附近的程序。 2> …

AI大模型的战场 通用大模型 vs. 垂直大模型

目录 前言1 通用大模型1.1 通用大模型简介1.2 通用大模型的优势1.3 通用大模型的挑战 2 垂直大模型2.1 垂直大模型简介2.2 垂直大模型的优势2.3 垂直大模型的挑战 3 通用大模型 vs. 垂直大模型3.1 技术层面的比较3.2 商业层面的比较3.3 未来的发展趋势 结语 前言 随着人工智能…

直播预约丨《指标体系建设实战》第三期:指标平台功能架构及落地实践

指标是反映企业的各项核心业务活动、管理成效的数据体系&#xff0c;指标体系作为联结业务逻辑与数据实体的关键桥梁&#xff0c;是构建高质量数据统计的基础单元&#xff0c;并在量化业务绩效和效果评估中扮演着核心角色。 为了更好地服务于客户并提供切实可行的实践指导&…

idea插件开发之通过纯编码方式开发页面(不使用form ui)

写在前面 本文看线如何通过纯编码方式来定义页面。 1&#xff1a;正戏 我们首先来定义一个面板&#xff0c;需要继承抽象类&#xff1a;com.intellij.openapi.ui.SimpleToolWindowPanel&#xff0c;如下&#xff1a; public class MySelfDefinePanel extends SimpleToolWin…