记一次系统单点登录、模拟web系统登录方式的开发过程,使用AES加密

1.系统原始登录方式

访问登录页 

输入账号密码登录后

 2.从登录页找进去,从代码层面查看系统登录逻辑

常规登录方式为前端ajax请求LoginService服务-->返回200则跳转到home系统首页

 查看LoginService登录逻辑

后台获取ajax传递的信息-->比较验证码-->查询用户表-->如果存在用户-->比较密码-->如果密码正确-->登录信息存入session

3. 单点登录设计

因为单点登录的用户为第三方系统用户,我这边的系统是不存在的该用户的,正常的创建用户的流程

维护机构角色-->维护用户-->维护用户所属角色

 

单点登录的用户我不可能说让他们把需要把用户预先把我这边的系统创建好,并分配角色

对于我这边系统没注册的用户我需要后台代码实现注册用户,绑定角色

我这边的系统为多机构版本,首先单点登录的机构我预先维护好一个角色,然后新用户进来我后台实现注册用户,绑定角色

约定第三方单点登录需要的信息

拼接好以下字符串

userCode=huuweq&userName=张三1号&orgId=65

使用AES算法加密拼接好的字符串,加密完成后进行URL编码生成userToken

4.代码记录

4.1 SsoAction.java

package bsoft.wsyyPlatform.action;import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import bsoft.lis.base.Service;
import bsoft.lis.login.LoginService;
import bsoft.lis.tools.MD5;
import bsoft.wsyyPlatform.service.SsoService;
import bsoft.wsyyPlatform.utils.AESUtil;
import bsoft.wsyyPlatform.utils.SimpleQueryHelper;/*** * @author gaom* 2021-09-13* 武汉东西湖卫生局需求 单点登录入口**/
@Controller
public class SsoAction {public static final Logger logger=LoggerFactory.getLogger(SsoAction.class);@Autowiredpublic SsoService ssoService;//调用登录服务加签使用的keypublic static final String invoke_loginService_key="B8736EF7AD0A233FB5E0C7D8A2EEBEE6";//单点登录aes加密keypublic static final String sso_key="ffbbfcd692e84d6b82af1b5c0e6f5446";public static final Set<String> sso_orglist=new HashSet<String>();static{//开放单点登录的机构String[] sso_ary=new String[]{"65","66","67","68","69","70","71","72","73","74","75","76"};for(String sso_str:sso_ary){sso_orglist.add(sso_str);}}@RequestMapping(value="ssoAction_ssoLogin.do")public void ssoAction_ssoLogin(HttpServletRequest request,HttpServletResponse response){//String logonName=request.getParameter("logonName");//String orgId=request.getParameter("orgId");//用户tokenSimpleQueryHelper sh=new SimpleQueryHelper();String userToken=request.getParameter("userToken");response.setContentType("text/html;charset=UTF-8");Map<String,Object> reqMap=new HashMap<String,Object>();Map<String,Object> resMap=new HashMap<String,Object>();try{userToken=request.getParameter("userToken");if(userToken==null||userToken.length()==0){resMap.put("code", 301);resMap.put("message", "error,userToken must not be empty!");sh.outputObject(response, resMap);return;}logger.info("ssoAction_ssoLogin userToken:"+userToken);//解密String userMessage=AESUtil.decrypt(userToken,sso_key);logger.info("ssoAction_ssoLogin userToken:"+userToken+"--> userMessage:"+userMessage);//String userMessage="userCode=huuweq&userName=张三1号&orgId=65";String[] userMessageAry= userMessage.split("&");String userCode=(userMessageAry[0].split("="))[1];String userName=(userMessageAry[1].split("="))[1];String orgId=(userMessageAry[2].split("="))[1];if(!sso_orglist.contains(orgId)){resMap.put("code", 301);resMap.put("message", "error,orgId:"+orgId+" not support SSO!");sh.outputObject(response, resMap);return;}reqMap.put("userCode", userCode);reqMap.put("userName", userName);reqMap.put("orgId", orgId);//单点登录检查用户和角色 不存在则新建ssoService.ssoCheck(reqMap, resMap);logger.info("ssoService.ssoCheck resMap:"+resMap.toString());int code=Integer.parseInt(resMap.get("code")+"");if(code!=200){//用户角色检查失败  sh.outputObject(response, resMap);return;}//用户 角色检查好后 执行单点登录ssoService.ssoLogin(reqMap, resMap);code=Integer.parseInt(resMap.get("code")+"");if(code!=200){//用户角色检查失败  sh.outputObject(response, resMap);return;}//调用系统登录服务HashMap<String, Object> resMap_loginService = ssoService.invokeLoginServoce(request, response, userCode);String code_service=resMap_loginService.get(Service.RES_CODE)+"";String message_service=resMap_loginService.get(Service.RES_MESSAGE)+"";logger.info("ssoAction_ssoLogin loginService.execute--> code_service:"+code_service+"       message_service:"+message_service);if(code_service.length()>0&&(!"null".equals(code_service))){//报错 resMap.put("code", 301);resMap.put("message", "ssoAction_ssoLogin loginService.execute  ");sh.outputObject(response, resMap);return;}//调用LoginService登录方法成功后,会生成用户session,直接重定向到系统首页即可response.sendRedirect("/wsyyPlatform/NewFrame/home.html");}catch(Exception e){e.printStackTrace();sh.outputException(response, "SSO exception", e);logger.error("ssoAction_checkLogin userToken:"+userToken+" Exception :"+e.getMessage());}}public static void main(String[] args) {String userMessage="userCode=zqjwsy&userName=张三1号&orgId=71";try {String encryptStr = AESUtil.encrypt(userMessage, sso_key);String encrypt_encodeStr= URLEncoder.encode(encryptStr);System.out.println("AES加密:"+encryptStr);System.out.println("URL编码:"+encrypt_encodeStr);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

4.2 SsoService.java

package bsoft.wsyyPlatform.service;import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import bsoft.lis.login.LoginService;
import bsoft.lis.tools.MD5;
import bsoft.wsyyPlatform.action.SsoAction;
import bsoft.wsyyPlatform.dao.SsoDao;/*** 单点登录服务* @author gaom* 2021-09-13*/
@Service
public class SsoService {@Autowiredpublic SsoDao ssoDao;/*** 单点登录检查用户角色服务* 新用户则创建 不存在角色则创建角色* @param reqMap* @param resMap*/public void ssoCheck(Map<String,Object> reqMap,Map<String,Object> resMap){String userCode=reqMap.get("userCode")+"";String userName=reqMap.get("userName")+"";String orgId=reqMap.get("orgId")+"";//获取机构角色List<String> orgRoleList=ssoDao.getOrgRole(orgId);if(orgRoleList.size()==0){resMap.put("code", 301);resMap.put("message", "单点登录失败,reqMap:"+reqMap.toString()+" 没有找到机构初始角色");return;}String orgRoleId=orgRoleList.get(0);List<Map<String,Object>> userList=ssoDao.getUserList(userCode);if(userList.size()==0){//初次登录 初始化用户String yhid=ssoDao.createUser(userCode, userName, orgId);//初始化角色ssoDao.createUserRole(yhid, orgId, orgRoleId);resMap.put("code", 200);resMap.put("message", "单点登录用户认证成功,新用户,已创建用户和角色,reqMap:"+reqMap.toString());return;}//已有用户Map<String,Object> userMap=userList.get(0);String userMap_jgid=userMap.get("JGID")+"";if(!userMap_jgid.equals(orgId)){resMap.put("code", 301);resMap.put("message", "单点登录失败,reqMap:"+reqMap.toString()+" 单点登录的用户所属机构和用户已绑定机构冲突 单点登录机构:"+orgId+"  用户已绑定机构:"+userMap_jgid);return;}//机构一致 验证是否有角色 String userMap_yhid=userMap.get("YHID")+"";List<Map<String,Object>> userRoleList=ssoDao.getUserRole(userMap_yhid);if(userRoleList.size()==0){//没角色//维护角色ssoDao.createUserRole(userMap_yhid, orgId, orgRoleId);resMap.put("code", 200);resMap.put("message", "单点登录用户认证成功,已存在用户,没角色,已创建角色,reqMap:"+reqMap.toString());return; }resMap.put("code", 200);resMap.put("message", "单点登录用户认证成功,已存在用户,已存在角色,reqMap:"+reqMap.toString());return; }/*** 单点登录服务* 用户角色检查完成后 执行登录操作* @param reqMap* @param resMap*/public void ssoLogin(Map<String,Object> reqMap,Map<String,Object> resMap){String userCode=reqMap.get("userCode")+"";String userName=reqMap.get("userName")+"";String orgId=reqMap.get("orgId")+"";List<Map<String,Object>> userList=ssoDao.getUserList(userCode);if(userList.size()==0){//异常 理论上验证用户通过 不会出现 查不到用户resMap.put("code", 301);resMap.put("message", "单点登录失败,reqMap:"+reqMap.toString()+" 用户ssoLogin登录失败,无效的用户名!");return;}resMap.put("code", 200);resMap.put("userMap", userList.get(0));}/*** 调用系统登录服务* @param request* @param response* @param userCode* @return*/public HashMap<String, Object> invokeLoginServoce(HttpServletRequest request, HttpServletResponse response,String userCode) {LoginService loginService=	bsoft.wsyyManager.utils.AppContextHolder.getBean("LoginService", LoginService.class);HashMap<String, Object> reqMap_loginService=new HashMap();HashMap<String, Object> resMap_loginService=new HashMap();reqMap_loginService.put("userid", userCode);reqMap_loginService.put("checkSource", "SSO");//登录来源 SSO为单点登录String invoke_loginService_sign=MD5.getMD5(userCode+SsoAction.invoke_loginService_key).toUpperCase();//签名reqMap_loginService.put("invoke_loginService_sign", invoke_loginService_sign);WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());loginService.initServerlet(request, response, webApplicationContext);loginService.execute(reqMap_loginService,resMap_loginService);return resMap_loginService;}}

4.3 SsoDao.java

package bsoft.wsyyPlatform.dao;import java.util.List;
import java.util.Map;import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.springframework.stereotype.Repository;import bsoft.wsyyPlatform.utils.DaoUtil;/*** 单点登录Dao层* @author gaom* 2021-09-13*/
@Repository
public class SsoDao extends DaoUtil{/*** 根据用户代码获取用户信息* @param userCode* @return 用户信息*/@SuppressWarnings("unchecked")public List<Map<String,Object>> getUserList(String userCode){Session session=null;try{session=getMySessionFactory_tjxt().openSession();List<Map<String,Object>> userList=session.createSQLQuery(" select * from yypt_xtyhb where YHDM=:YHDM ").setParameter("YHDM", userCode).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();return userList;}finally{if(session!=null){session.close();}}} /*** 根据机构ID获取该机构已维护的角色* @param orgId* @return 机构已维护好的角色*/@SuppressWarnings("unchecked")public List<String> getOrgRole(String orgId){Session session=null;try{session=getMySessionFactory_tjxt().openSession();//取每个机构新建的第一个角色  第一个角色一般为医院管理员List<String> orgRoleList=session.createSQLQuery(" select cast(ROLEID as char) from pt_role where JGID=:JGID order by ROLEID asc limit 0,1 ").setParameter("JGID", orgId).list();return orgRoleList;}finally{if(session!=null){session.close();}}} /*** 根据用户ID获取用户是否已维护角色* @param userCode* @return 用户角色*/@SuppressWarnings("unchecked")public List<Map<String,Object>> getUserRole(String yhid){Session session=null;try{session=getMySessionFactory_tjxt().openSession();List<Map<String,Object>> userRoleList=session.createSQLQuery(" select * from PT_USERROLE where YHID=:YHID ").setParameter("YHID", yhid).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();return userRoleList;}finally{if(session!=null){session.close();}}} /*** 首次单点登录 需创建用户* @param userCode* @param userName* @param orgId* @return*/@SuppressWarnings("unchecked")public String createUser(String userCode,String userName,String orgId){Session session=null;try{session=getMySessionFactory_tjxt().openSession();int thenUserId=1;Object o=session.createSQLQuery(" select  max(CAST(yhid as SIGNED  ))   from yypt_xtyhb ").uniqueResult();if(o!=null){thenUserId=Integer.parseInt(o+"")+1;}String createUserSql="insert into YYPT_XTYHB(YHID,YHDM,YHXM,YHMM,ZXBZ,PYJM,JGID)" +"values" +"(:YHID,:YHDM,:YHXM,:YHMM,:ZXBZ,:PYJM,:JGID)";session.createSQLQuery(createUserSql).setParameter("YHID", thenUserId).setParameter("YHDM", userCode).setParameter("YHXM", userName)//密码明文 ghyu531  单点注册的用户统一使用该密码.setParameter("YHMM", "86417ee52e1928e952ec701f98452ae2").setParameter("ZXBZ", "0").setParameter("PYJM", "").setParameter("JGID", orgId).executeUpdate();return thenUserId+"";}finally{if(session!=null){session.close();}}} /*** 创建用户对应的角色* @param yhid* @param orgId* @param orgRoleId* @return*/@SuppressWarnings("unchecked")public int createUserRole(String yhid,String orgId,String orgRoleId){Session session=null;try{session=getMySessionFactory_tjxt().openSession();int thenTid=1;Object o=session.createSQLQuery(" select  max(tid)   from PT_USERROLE ").uniqueResult();if(o!=null){thenTid=Integer.parseInt(o+"")+1;}String createUserSql=" insert into PT_USERROLE(TID,YHID,JGID,ROLEID)values(:TID,:YHID,:JGID,:ROLEID) ";int execRtn=session.createSQLQuery(createUserSql).setParameter("TID", thenTid).setParameter("YHID", yhid).setParameter("JGID", orgId).setParameter("ROLEID", orgRoleId).executeUpdate();return execRtn;}finally{if(session!=null){session.close();}}} }

4.4 AESUtil.java

package bsoft.wsyyPlatform.utils;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;import java.net.URLEncoder;
import java.security.SecureRandom;/*** description:AES 对称可逆解密算法* AEs单钥 加密效率高   hash算法 不可以用于签名* RSA可以用于签名 而且RSA签名算法也是双钥  常用的签名算法还有 MD5 签名 因为MD5是不可逆加密* date: 2021/8/5* author: gaom* version: 1.0*/
public class AESUtil {private static final int BYTE_LENGTH = 128;private static final String $UTF8 = "UTF-8";public static void main(String[] args) {String userMessage="userCode=huuweq&userName=张三1号&orgId=65";try {String encryptStr = AESUtil.encrypt(userMessage, "ffbbfcd692e84d6b82af1b5c0e6f5446");String encrypt_encodeStr= URLEncoder.encode(encryptStr);System.out.println("AES加密:"+encryptStr);System.out.println("URL编码:"+encrypt_encodeStr);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}/*** AES加密* AES为对称加密算法  及加密和解密的 key一样 和RSA非对称加密各有优缺点* AES单钥 加密效率高   hash算法 不可以用于签名* RSA双钥  加密效率低,除了加密 还有签名功能* @param content  需要加密的明文* @param key  钥匙* @return* @throws Exception*/public static String encrypt(String content, String key) throws Exception {try {byte[] contentByte=content.getBytes($UTF8);KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");secureRandom.setSeed(key.getBytes());keyGenerator.init(BYTE_LENGTH, secureRandom);SecretKey secretKey = keyGenerator.generateKey();byte[] encodeFormat = secretKey.getEncoded();SecretKeySpec secretKeySpec = new SecretKeySpec(encodeFormat, "AES");Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// 正式执行加密操作byte[] encryptByte=cipher.doFinal(contentByte);//二进制不方便web传输  转为base64编码方便传输  String base64EncryptData=org.apache.commons.codec.binary.Base64.encodeBase64String(encryptByte);return base64EncryptData;} catch (Exception e) {System.out.println("encrypt异常 :"+e.getMessage());throw new Exception(e);}}/***AES解密* @param base64Content  已经base64编码的密文 加密默认返回byte 转为base64方便web传输* @param key  钥匙* @return* @throws Exception*/public static String decrypt(String base64Content, String key) throws Exception {try {//base64 解码  byte[] contentByte=org.apache.commons.codec.binary.Base64.decodeBase64(base64Content);KeyGenerator kgen = KeyGenerator.getInstance("AES");SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");secureRandom.setSeed(key.getBytes());kgen.init(BYTE_LENGTH, secureRandom);SecretKey secretKey = kgen.generateKey();byte[] encodeFormat = secretKey.getEncoded();SecretKeySpec secretKeySpec = new SecretKeySpec(encodeFormat, "AES");// Cipher对象实际完成加密操作Cipher cipher = Cipher.getInstance("AES");// 用密匙初始化Cipher对象cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);// 正式执行解密操作byte[] decryptByte=cipher.doFinal(contentByte);//返回byte转为string String  decryptData=new String(decryptByte,$UTF8);return  decryptData;} catch (Exception e) {System.out.println("decrypt异常 :"+e.getMessage());throw new Exception(e);}}}

4.5 LoginService.java修改,新增支持单点登录

package bsoft.lis.login;import javax.servlet.http.HttpSession;
import com.oa.output.*;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.servlet.http.HttpServletRequest;
import java.util.*;import bsoft.lis.base.*;
import bsoft.lis.tools.*;
import bsoft.wsyyPlatform.action.SsoAction;import com.oa.base.*;public class LoginService extends BaseBean {@Overridepublic void execute(HashMap<String, Object> req, HashMap<String, Object> res) {try {super.execute(req, res);String userid2 = "";String UnitCode2 = "";String userid = (String) req.get("userid");// 用户名String password = (String) req.get("password");// 密码//2021-9-22 gaom add  增加支持单点登录的逻辑String checkSource = req.get("checkSource")+"";// 登录来源 SSO为单点登录String invoke_loginService_sign = req.get("invoke_loginService_sign")+"";// 签名String sign_this=MD5.getMD5(userid+SsoAction.invoke_loginService_key).toUpperCase();String validation = req.get("validation")+"";// 是否验证码//2021-9-22 单点登录if("SSO".equals(checkSource)){//单点登录需要签名认证,只有SsoAction单点登录入口才有签名key,防止非法绕过SsoAction采用单点登录if(!invoke_loginService_sign.equals(sign_this)){res.put(Service.RES_CODE, 400);res.put(Service.RES_MESSAGE, "SSO无效的签名!");return;}//单点登录不需要图片验证码validation="false";}String UnitCode = "";UnitCode = (String) req.get("UnitCode");// 机构或单位编号String sVerifyCode = (String) req.get("sVerifyCode");// 验证码String VerifyCode2 = "";String ip = this.getHttpServletRequest().getLocalAddr();VerifyCode2 = RandomValidateCode.RANDOMCODEKEYMap.get(ip)+ "";if (validation.equalsIgnoreCase("true")) {Object lo = this.getSession().getAttribute("RANDOMVALIDATECODEKEY");String VerifyCode = "";if (lo == null){VerifyCode = "";}else{VerifyCode = lo.toString();}if (!sVerifyCode.equalsIgnoreCase(VerifyCode)) {VerifyCode2=VerifyCode2.toUpperCase();sVerifyCode=sVerifyCode.toUpperCase();if (!VerifyCode2.equals(sVerifyCode)) {//if (VerifyCode2.indexOf(sVerifyCode) < 0) {res.put(Service.RES_CODE, 400);res.put(Service.RES_MESSAGE, "验证码不正确!");return;}}}this.ConnectLisDB();User lUser = new User();int il_ret = lUser.of_login(checkSource,userid, password, UnitCode, this);if (il_ret < 0) {res.put(Service.RES_CODE, 400);res.put(Service.RES_MESSAGE, lUser.returnmsg);return;}} catch (Exception e) {logger.info(ErrorMsg.info(e));res.put(Service.RES_CODE, 400);res.put(Service.RES_MESSAGE, ErrorMsg.info(e));return;}finally{this.CloseDB();}}}

5.最终的效果

访问单点登录URL

userToken生成方式见 SsoAction的main方法

http://127.0.0.1:8085/wsyyPlatform/ssoAction_ssoLogin.do?userToken=6U7VW97GmfeJU0alQkUBoaHm25fLLlpMhw2gtjIS8Dvd%2Fyf5UDJu%2F13q8uphEq0V

单点登录成功重定向到首页

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iPhone mini,永远再见了

世界属于多数派&#xff0c;尽管有极少数人对 iPhone mini 情有独钟&#xff0c;但因为销量惨淡&#xff0c;iPhone mini 还是逃不开停产的命运。 据 Counterpoint 的数据&#xff0c;iPhone 12/13 mini 两代机型&#xff0c;仅占同期 iPhone 销量的 5%。 因为是小屏手机&…

监控易一体化运维:监控易机房管理,打造高效智能机房

在数字化浪潮中&#xff0c;企业对数据中心和机房的依赖程度与日俱增&#xff0c;机房的稳定运行成为业务持续开展的关键支撑。信息化的变迁&#xff0c;见证了机房管理从传统模式向智能化、精细化转变的过程。今天&#xff0c;就为大家深度剖析监控易在机房管理方面的卓越表现…

概率与决策理论

1.Q-learning Q-Learning 是一种无模型&#xff08;model-free&#xff09;强化学习算法&#xff0c;用于学习在马尔可夫决策过程&#xff08;MDP&#xff09;中的最优策略。它通过迭代更新 ​Q 值&#xff08;动作价值函数&#xff09;​ 来估计在某个状态下采取某个动作的长…

Python 学习路线推荐

文章目录 一、基础语法学习1.学习资源2.学习建议 二、数据处理与分析方向1. 数据处理库学习学习资源实践示例 2. 数据可视化实践示例 三、Web 开发方向1. Web 框架选择与学习学习资源实践示例 2. 前端知识补充学习资源 四、人工智能与机器学习方向1. 机器学习基础学习资源实践示…

如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用

前言&#xff1a;最近&#xff0c;国产AI圈里的新星——Deepseek&#xff0c;简直是火到不行。但是&#xff0c;你是不是已经对那些千篇一律的手机APP和网页版体验感到腻味了&#xff1f;别急&#xff0c;今天就带你解锁一个超炫的操作&#xff1a;在你的Windows电脑上本地部署…

SpringCloud+Mybatis-Plus+Docker+RabbitMQ+Redis+Elasticsearch黑马商城

一.MyBatis—Plus 一.快速入门 MybatisPlus介绍&#xff1a;MybatisPlus是一个基于Mybatis的增强工具库&#xff0c;旨在简化开发、提升效率&#xff0c;同时保留Mybatis的灵活性。它在Mybatis的基础上只做增强不做改变&#xff0c;引入它不会对现有工程产生影响 官网&#…

01 相机标定与相机模型介绍

学完本文,您将了解不同相机模型分类、内参意义,及对应的应用代码模型 标定的意义 建模三维世界点投影到二维图像平面的过程。标定输出的是相机模型。 相机模型 相机模型可以解理解为投影模型 +

如何在 Postman 中正确设置 Session 以维持用户状态?

在 Postman 里面设置有 session 的请求。如果你还不知道什么是 session&#xff0c;那么请看这里—— session 是一种记录客户端和服务器之间状态的机制&#xff0c;用于保持用户的登录状态或者其他数据&#xff0c;从而让用户在不同页面之间保持一致的体验。 Postman 设置带 …

免费使用!OpenAI 全量开放 GPT-4o 图像生成能力!

2025年3月26日&#xff0c;OpenAI正式推出GPT-4o原生图像生成功能&#xff0c;这一更新不仅标志着多模态AI技术的重大突破&#xff0c;更引发了全球AI厂商的激烈竞争。从免费用户到企业开发者&#xff0c;从创意设计到科学可视化&#xff0c;GPT-4o正在重塑图像生成的边界。本文…

【JavaScript】八、对象

文章目录 1、对象的声明2、对象的使用3、对象中的方法4、遍历对象5、内置对象Math 1、对象的声明 一种数据类型&#xff0c;使用typeof查看类型&#xff0c;结果是object可以详细的描述描述某个事物 声明语法&#xff1a; // 多用花括号形式声明 // 比如声明一个person对象 …

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

DataGear 企业版 1.4.0 发布,数据可视化分析平台

DataGear 企业版 1.4.0 已发布&#xff0c;欢迎体验&#xff01; http://datagear.tech/pro/ 企业版 1.4.0 看板可视编辑模式新增了插入看板表单/面板布局、编辑图表联动、复制/粘贴、撤销/恢复等功能&#xff0c;具体更新内容如下&#xff1a; 新增&#xff1a;看板可视编辑…

windows第十八章 菜单、工具栏、状态栏

文章目录 创建框架窗口菜单菜单的风格通过资源创建菜单菜单的各种使用通过代码创建菜单在鼠标位置右键弹出菜单 CMenu常用函数介绍工具栏方式一&#xff0c;从资源创建工具栏方式二&#xff0c;代码创建 状态栏状态栏基础创建状态栏 创建框架窗口 手动创建一个空项目&#xff…

局域网共享失败?打印机/文件夹共享工具

很多时候&#xff0c;在办公或家庭环境中&#xff0c;我们需要进行打印机和文件夹的共享&#xff0c;以便更高效地协作和处理文件。然而&#xff0c;寻找对应版本的共享设置或是不想花费太多时间去进行复杂的电脑设置&#xff0c;总是让人感到头疼。今天&#xff0c;我要向大家…

C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因

文章目录 原因分析解决方案1. 检查记录集是否为空2. 安全调用COM方法3.进行异常捕获4. 替代方案&#xff1a;手动处理空数据 总结 在C中使用CopyFromRecordset将空记录集&#xff08;0条记录&#xff09;复制到Excel时崩溃的原因及解决方法如下&#xff1a; 原因分析 空记录集…

torchvision中数据集的使用

1、torchvision及其数据集的介绍 1.1 torchvision介绍 torchvision 是 PyTorch 的一个官方库&#xff0c;专门用于计算机视觉任务。它提供了以下核心功能&#xff1a; 预训练模型&#xff1a;如 ResNet、VGG、EfficientNet 等。数据集&#xff1a;内置常用视觉数据集&#xf…

d2025328

一、sql-判断三角形 610. 判断三角形 - 力扣&#xff08;LeetCode&#xff09; 用一下if加上判断条件 select x,y,z,if(xy > z and xz > y and yz > x and x-y < z and x-z < y and y-z < x,Yes,No) as triangle from Triangle 二、按照分类统计薪水 190…

C++20新特性:std::assume_aligned详解

文章目录 一、概述二、函数定义与语法三、使用方法与注意事项1. 使用方法2. 注意事项 四、性能优化原理五、实际应用场景六、编译器支持情况七、总结 一、概述 C20引入了std::assume_aligned&#xff0c;这是一个非常实用的特性&#xff0c;用于告知编译器某个指针所指向的对象…

洛谷P1706 全排列题解

P1706 全排列问题 题目描述 按照字典序输出自然数 1 1 1 到 n n n 所有不重复的排列&#xff0c;即 n n n 的全排列&#xff0c;要求所产生的任一数字序列中不允许出现重复的数字。 输入格式 一个整数 n n n。 输出格式 由 1 ∼ n 1 \sim n 1∼n 组成的所有不重复的…

yum install 报错(CentOS换源):

yum instally yum utils device mapper persistent-data lvm2 报错&#xff1a; 排查错误原因&#xff1a;centos7 系统停止维护了 解决方案&#xff1a;换源&#xff08;更换操作系统&#xff09; //1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-…