在这篇文章里面主要讲解如何在mybatis里面使用一对一、一对多、多表联合查询(类似视图)操作的例子。 注:阅读本文前请先大概看一下之前两篇文章。 一、表结构 班级表class,学生表student,班级学生关系表ClassStudent。 这里一个学生只会在一个班级里面,也就是一对一的关系;一个班级有多个学生,也就是一对多的关系。 结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
CREATE TABLE [dbo].[Class]( [class_id] [int] NOT NULL, [class_name] [varchar](50) NOT NULL, CONSTRAINT [PK_Class] PRIMARY KEY CLUSTERED ( [class_id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] CREATE TABLE [dbo].[ClassStudent]( [class_id] [int] NOT NULL, [student_id] [int] NOT NULL ) ON [PRIMARY] CREATE TABLE [dbo].[Student]( [s_id] [int] NOT NULL, [s_name] [varchar](50) NOT NULL, CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED ( [s_id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] |
3张表的数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
insert into Class values(1,'三(1)班') insert into Class values(2,'三(2)班') insert into Class values(3,'三(3)班') insert into Class values(4,'三(4)班') insert into Student values(1001,'张三') insert into Student values(1002,'李四') insert into Student values(1003,'赵五') insert into Student values(1004,'王二麻子') insert into ClassStudent values(1,1001) insert into ClassStudent values(1,1003) insert into ClassStudent values(4,1002) insert into ClassStudent values(3,1004) |
二、在原项目下新建一个包com.mybatis.sqljoinrelation,在包里面新建一个sqlMapper.xml的映射文件,在项目的mybatis的配置文件conf.xml中对这个sqlMapper.xml进行注册,注册片段如下:
1 2 3 4 |
<!-- 注册映射文件 --> <mappers> <mapper resource="com/mybatis/sqljoinrelation/sqlMapper.xml" /> </mappers> |
紧接着在原项目下再新建一个包com.mybatis.bean,在里面新建实体类 学生:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.mybatis.bean; /** * 学生(临时) */ public class StudentTemp { private int studentid; private String studentname; private Class tempClass; public Class getTempClass() { return tempClass; } public void setTempClass(Class tempClass) { this.tempClass = tempClass; } public int getStudentid() { return studentid; } public void setStudentid(int studentid) { this.studentid = studentid; } public String getStudentname() { return studentname; } public void setStudentname(String studentname) { this.studentname = studentname; } @Override public String toString() { return "StudentTemp [studentid=" + studentid + ", studentname=" + studentname + ", tempClass=" + tempClass + "]"; } } |
班级:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.mybatis.bean; /** * 班级 */ public class Class { private int classid; private String classname; public int getClassid() { return classid; } public void setClassid(int classid) { this.classid = classid; } public String getClassname() { return classname; } public void setClassname(String classname) { this.classname = classname; } @Override public String toString() { return "Class [classid=" + classid + ", classname=" + classname + "]"; } } |
学生班级视图类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.mybatis.bean; public class studentclass { private int s_id; private String s_name; private int class_id; private String class_name; public int getS_id() { return s_id; } public void setS_id(int s_id) { this.s_id = s_id; } public String getS_name() { return s_name; } public void setS_name(String s_name) { this.s_name = s_name; } public int getClass_id() { return class_id; } public void setClass_id(int class_id) { this.class_id = class_id; } public String getClass_name() { return class_name; } public void setClass_name(String class_name) { this.class_name = class_name; } @Override public String toString() { return "studentclass [s_id=" + s_id + ", s_name=" + s_name + ", class_id=" + class_id + ", class_name=" + class_name + "]"; } } |
三、查询操作 1、 一对一,查询学生编号等于1001且他所在班级信息 2、一对多,查询班级编号等于1且包含所有学生信息 3、类似视图查询学生编号等于1001且他所在班级信息 sqlMapper.xml如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?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.mybatis.sqljoinrelation.sqlMapper"> <!-- 1、 获取某学生以及该学生所在班级的信息 --> <!-- 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明, 如果用"*"代替,则mybatis会自动匹配resultMap中提供的列名 --> <select id="getStudentAndClass" parameterType="int" resultMap="studentClassMap"> select c.class_id,c.class_name,s.s_id,s.s_name from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where s.s_id = #{id} </select> <!-- resultMap中的type表示返回什么类型的对象 --> <resultMap type="com.mybatis.bean.StudentTemp" id="studentClassMap"> <!-- property 表示com.mybatis.bean.StudentTemp中的属性; column 表示表中的列名 --> <id property="studentid" column="s_id" /> <result property="studentname" column="s_name" /> <!-- association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象 --> <association property="tempClass" javaType="com.mybatis.bean.Class"> <!-- property 表示com.mybatis.bean.Class中的属性; column 表示表中的列名 --> <id property="classid" column="class_id" /> <result property="classname" column="class_name" /> </association> </resultMap> <!-- 2、获取某学生以及该学生所在班级的信息,类似视图实现方式 --> <!-- resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样; resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射 --> <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass"> select c.class_id,c.class_name,s.s_id,s.s_name from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where s.s_id = #{id} </select> <!-- 3、获取某班级以及班级里面所有学生的信息 --> <select id="getClassStudents" parameterType="int" resultMap="classStudentsMap"> select * from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where c.class_id = #{id} </select> <resultMap type="com.mybatis.bean.ClassTemp" id="classStudentsMap"> <id property="classid" column="class_id"/> <result property="classname" column="class_name"/> <!-- property表示集合类型属性名称,ofType表示集合中的对象是什么类型 --> <collection property="students" ofType="com.mybatis.bean.Student"> <id property="studentid" column="s_id"/> <result property="studentname" column="s_name"/> </collection> </resultMap> </mapper> |
测试代码如下: 一对一与类似视图查询的代码在一起,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.mybatis.sqljoinrelation; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import com.mybatis.util.MybatisUtils; /** * 一对一 */ public class testonetoone { public static void main(String[] args) { SqlSessionFactory factory = MybatisUtils.getFactory(); SqlSession session = null; try { session = factory.openSession(true); //1、StudentTemp String statement1 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClass"; System.out.println(session.selectOne(statement1, 1001)); //2、用model类型接收数据 String statement2 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClassView"; System.out.println(session.selectOne(statement2, 1001)); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } } } |
一对多测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package com.mybatis.sqljoinrelation; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import com.mybatis.util.MybatisUtils; /** * 一对多 */ public class testonetomany { public static void main(String[] args) { SqlSessionFactory factory = MybatisUtils.getFactory(); SqlSession session = null; try { session = factory.openSession(true); //1、StudentTemp String statement = "com.mybatis.sqljoinrelation.sqlMapper.getClassStudents"; System.out.println(session.selectOne(statement, 1)); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } } } |
四、sqlMapper.xml需要说明的问题 1、一对一:<association property="tempClass" javaType="com.mybatis.bean.Class"> association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象 2、类似视图查询: <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass"> resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样; resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射,其中一对一与一对多都是用resultMap来映射 3、一对多:<collection property="students" ofType="com.mybatis.bean.Student"> collection字面意思是集合,这里专门做一对多关联 ,property表示集合类型属性名称,ofType表示集合中的对象是什么类型 4、<select>select * from …</student>与<select>select 字段1,字段2,字段3… from …</student> 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,如果用"*"代替,则mybatis会自动匹配resultMap或者resultType中提供的列名, 如果某对象存在列映射的属性,但是在select 后面找不到这个列,则在返回结果中,该列多映射的值为null。 至此,对于一对一、一对多、视图查询都能很好的解决,主要还是要重点关注第四点说明。 from:https://www.cnblogs.com/wucj/p/5148813.html
View Details1. 报错信息
1 2 3 4 5 6 7 8 |
Description: The bean 'dataSource', defined in BeanDefinition defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class] and overriding is disabled. Action: Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true |
2. 原因
1 2 |
相同名字不成功 |
3. 解决办法
1 2 3 4 |
main: allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册 |
from:https://blog.csdn.net/weixin_42633131/article/details/84782516
View Details原创于 【模棱博客】 Spring Webflux和Spring Web是两个完全不同的Web栈。 然而, Spring Webflux继续支持基于注解的编程模型 使用这两个堆栈定义的端点可能看起来相似,但测试这种端点的方式是相当不同的,写这样一个端点的用户必须知道哪个堆栈处于活动状态并据此制定测试。 样品端点 考虑一个基于示例注释的端点: import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController data class Greeting(val message: String) @RestController @RequestMapping("/web") class GreetingController { @PostMapping("/greet") fun handleGreeting(@RequestBody greeting: Greeting): Greeting { return Greeting("Thanks: ${greeting.message}") } } 使用Spring Web进行测试 如果Spring Boot 2启动器用于使用Spring Web作为启动器创建此应用程序,则按以下方式使用Gradle构建文件指定: compile('org.springframework.boot:spring-boot-starter-web') 那么这样一个端点的测试将会使用一个Mock web运行时,被称为Mock MVC : import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content @RunWith(SpringRunner::class) @WebMvcTest(GreetingController::class) class GreetingControllerMockMvcTest { @Autowired lateinit var mockMvc: MockMvc @Test fun testHandleGreetings() { mockMvc .perform( post("/web/greet") .content(""" |{ |"message": "Hello Web" |} […]
View Details转自:百家号-薇薇心语 各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFlux。web? 不是已经有SpringMVC这么好用的东西了么,为啥又冒出个WebFlux? 这玩意儿是什么鬼? Spring WebFlux特性 特性一 异步非阻塞 众所周知,SpringMVC是同步阻塞的IO模型,资源浪费相对来说比较严重,当我们在处理一个比较耗时的任务时,例如:上传一个比较大的文件,首先,服务器的线程一直在等待接收文件,在这期间它就像个傻子一样等在那儿(放学别走),什么都干不了,好不容易等到文件来了并且接收完毕,我们又要将文件写入磁盘,在这写入的过程中,这根线程又再次懵bi了,又要等到文件写完才能去干其它的事情。这一前一后的等待,不浪费资源么? 没错,Spring WebFlux就是来解决这问题的,Spring WebFlux可以做到异步非阻塞。还是上面那上传文件的例子,Spring WebFlux是这样做的:线程发现文件还没准备好,就先去做其它事情,当文件准备好之后,通知这根线程来处理,当接收完毕写入磁盘的时候(根据具体情况选择是否做异步非阻塞),写入完毕后通知这根线程再来处理(异步非阻塞情况下)。这个用脚趾头都能看出相对SpringMVC而言,可以节省系统资源。666啊,有木有! 特性二 响应式(reactive)函数编程 如果你觉得java8的lambda写起来很爽,那么,你会再次喜欢上Spring WebFlux,因为它支持函数式编程,得益于对于reactive-stream的支持(通过reactor框架来实现的),喜欢java8 stream的又有福了。为什么要函数式编程? 这个别问我,我也不知道,或许是因为bi格高吧,哈哈,开玩笑啦。 特性三 不再拘束于Servlet容器 以前,我们的应用都运行于Servlet容器之中,例如我们大家最为熟悉的Tomcat, Jetty…等等。而现在Spring WebFlux不仅能运行于传统的Servlet容器中(前提是容器要支持Servlet3.1,因为非阻塞IO是使用了Servlet3.1的特性),还能运行在支持NIO的Netty和Undertow中。 所以,看完Spring WebFlux的新特性之后,内心五味杂陈的我,只能用一个表情来形容: 以上就是Spring WebFlux的主要的三大特性,当然,只是简单的介绍了一下,可能有些javaer对特性一中的所谓的IO模型这个还比较模糊,不要着急,下一次,咱就再介绍一下IO模型,这对后面理解这个框架是很有帮助的。Spring WebFlux是基于reactor框架之上的,reactor框架是对reactive-stream的实现,因此,后面还会详细介绍这两个东西,为了去理解Spring WebFlux框架的源码。 好啦,本篇是《深入浅出Spring Webflux系列》的第一篇,就到此结束啦。 我对自己的表现很满意,因为在没包含一行代码的情况下,居然把口水话都凑足了这么多字,哈哈。。。 另外,还是要到个歉,之前因为账号被盗,文章被人删除了,然后还乱发了几篇什么杂七杂八的广告文,问过头条客服,说不能恢复被删除的文章,这小心脏因此被伤了,所以连续半年多都没来更新了。 接下来,将更新《深入浅出Spring Webflux系列》等一系列文章,然后可能是JVM调优相关,到时候具体再看情况。 from:https://www.cnblogs.com/z-test/p/9438455.html
View Details1.在pom文件添加一行打包的配置
1 |
<packaging>jar</packaging> |
再添加一个spring-boot-maven-plugin打包插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> |
由于我的8080端口已经被占用了 ,所以我要先改下项目端口,如果你的8080端口没被占用不需要改 打开Run/Debug Configurations对话框添加一个Maven打包配置,如图 然后运行mvn就可以生成jar包 在项目的target目录可以看到生成的jar包 打开cmd,到jar 包所在目录 运行命令 java -jar springboot-0.0.1-SNAPSHOT.jar 浏览器访问结果 使用eclipse打成jar包 1.项目右键 debug as-> Debug Configurations 点击Debug即可。 当然你也可以选择打成war包,需要把pom里的jar改成war,打包后放到Tomcat的webapp下启动Tomcat就可以了。但是必须使用1.8的jdk和8.0以上的Tomcat ,且必须配置JAVA_HOME环境变量,这里我就不演示了。 from:https://blog.csdn.net/wya1993/article/details/79582014
View Details在pom文件中,添加如下即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> |
from:https://blog.csdn.net/qq_18769269/article/details/83095012
View Details【1】项目内部配置文件 spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
1 2 3 4 |
–file:./config/ –file:./ –classpath:/config/ –classpath:/ |
即如下图所示: 以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容。 SpringBoot会从这四个位置全部加载主配置文件,如果高优先级中配置文件属性与低优先级配置文件不冲突的属性,则会共同存在—互补配置。 我们也可以通过配置spring.config.location来改变默认配置。
1 2 |
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=D:/application.properties |
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置。 指定配置文件和默认加载的这些配置文件共同起作用形成互补配置。 【2】外部配置加载顺序 SpringBoot也可以从以下位置加载配置:优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置。 1.命令行参数 所有的配置都可以在命令行上进行指定; 多个配置用空格分开; –配置项=值
1 2 |
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc |
2.来自java:comp/env的JNDI属性 3.Java系统属性(System.getProperties()) 4.操作系统环境变量 5.RandomValuePropertySource配置的random.*属性值 6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件 7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件 8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件 9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件
1 |
由jar包外向jar包内进行寻找,优先加载待profile的,再加载不带profile的。 |
10.@Configuration注解类上的@PropertySource 11.通过SpringApplication.setDefaultProperties指定的默认属性 参考官网地址 官网图示如下: from:https://blog.csdn.net/j080624/article/details/80508606
View Details*eclipse默认tomcat下是自动完成编译;而Intellij Idea默认tomcat下不是自动完成编译,从如下开始设置: 进入“settings”,如下图找到“compiler”,选中如图框选选项 勾选“Build project automatically”,保存即可。 from:https://www.cnblogs.com/zdb292034/p/8047267.html
View Details第一步在我们的电脑上打开IntelliJ IDEA,点击File->Settings,如下图所示: 第二步进去Settings之后,点击 Compiler,如下图所示: 第三步勾选“Build project automatically”,点击OK,如下图所示: 第四步按“ctrl+alt+shift+/”键,选择Registry ,如下图所示: 第五步勾选“compiler.automake.allow.when.app.running”,保存之后,进行重启IntelliJ IDEA就完成了,如下图所示: from:https://jingyan.baidu.com/article/ca2d939d5b0c05eb6d31ce77.html
View Details前言 最近由于项目需求,服务端由c#编写,客户端由java编写。通信数据使用RSA非对称加密。但是java和c#生成的密钥格式是不一样的,所以需要转换格式才可以正常使用。网上搜到使用java进行格式转换的代码(如:http://blog.csdn.net/road2010/article/details/40071881 ),本文将给出一种c#的实现方法。 密钥格式 java密钥格式如下: 私钥: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKSZSSEdPhv77O5ocnLNGXeQ21qJDArC1+yId+9/pY5bXkZk5vCB49EpfMwNukLv6AJqofThZPNOs1t015fdEYIUnkIc2QVxRwa0xTeFP6N8D4WQXRWs4fNG27JK5kP45s+9KlJtx5hs7G97aMczehIWpHaO6j9inOmjlU8l62KZAgMBAAECgYEAmK3TRtMwRJb33OGnn9OeFumYfy92qxi3X6Hq1o6qDBW2qkd4bImfv+ni6AinyOVuaadt2Y+lq4dKGcCVJzoZvPm1VKxD2y7xKa8/vEbPRiRTt0qnPq9T7UJkpDsiXf/zOMfWdjc3uA1bPnQ65RWHSJ7zAE+Gd7xnyCE5MEyijLECQQDVYqQWDqOVLZ5lJUuIfUIrhv26GvuoTX8v60+opCz4/Mdfh6JlefICVD6SAaYvufXBHVFY26JicNlR62ZOiBoNAkEAxXhsuEnNJNQcQHEVTPZoulbMbTV1VZIDQ1zjG8fvu8sv6IBYcR5+EsC8n3/6RkW8/iCJDzxE++VHzhoSQSoDvQJBAM6/63J/rpndAIrJ7vyJOPLJsc9/U3SH2gMJAT7KC9UXvuldlsixtf3xuEpplKbLjEUXbfklnZm586a+6XqPvoUCQDFotltOLARBBmihYuEE7qNhQHk63QbyJ9rdDP5Qgo2Mg4o7QuXa6VSr4QZPsUGQBX/YiDLFs8ULU3IgV9zyNEkCQADAYR8DctYzg0eBGdcOrDA5Szc62pYrS2wk89wUxyL4FyDL3omkVMKvtu5tccy7Xht2ikJZRqefZ3dS7ASm8/4= 公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkmUkhHT4b++zuaHJyzRl3kNtaiQwKwtfsiHfvf6WOW15GZObwgePRKXzMDbpC7+gCaqH04WTzTrNbdNeX3RGCFJ5CHNkFcUcGtMU3hT+jfA+FkF0VrOHzRtuySuZD+ObPvSpSbceYbOxve2jHM3oSFqR2juo/Ypzpo5VPJetimQIDAQAB .NET密钥格式如下: 私钥:
1 2 3 4 5 6 7 8 9 10 |
<RSAKeyValue> <Modulus>pJlJIR0+G/vs7mhycs0Zd5DbWokMCsLX7Ih373+ljlteRmTm8IHj0Sl8zA26Qu/oAmqh9OFk806zW3TXl90RghSeQhzZBXFHBrTFN4U/o3wPhZBdFazh80bbskrmQ/jmz70qUm3HmGzsb3toxzN6Ehakdo7qP2Kc6aOVTyXrYpk=</Modulus> <Exponent>AQAB</Exponent> <P>1WKkFg6jlS2eZSVLiH1CK4b9uhr7qE1/L+tPqKQs+PzHX4eiZXnyAlQ+kgGmL7n1wR1RWNuiYnDZUetmTogaDQ==</P> <Q>xXhsuEnNJNQcQHEVTPZoulbMbTV1VZIDQ1zjG8fvu8sv6IBYcR5+EsC8n3/6RkW8/iCJDzxE++VHzhoSQSoDvQ==</Q> <DP>zr/rcn+umd0Aisnu/Ik48smxz39TdIfaAwkBPsoL1Re+6V2WyLG1/fG4SmmUpsuMRRdt+SWdmbnzpr7peo++hQ==</DP> <DQ>MWi2W04sBEEGaKFi4QTuo2FAeTrdBvIn2t0M/lCCjYyDijtC5drpVKvhBk+xQZAFf9iIMsWzxQtTciBX3PI0SQ==</DQ> <InverseQ>wGEfA3LWM4NHgRnXDqwwOUs3OtqWK0tsJPPcFMci+Bcgy96JpFTCr7bubXHMu14bdopCWUann2d3UuwEpvP+</InverseQ> <D>mK3TRtMwRJb33OGnn9OeFumYfy92qxi3X6Hq1o6qDBW2qkd4bImfv+ni6AinyOVuaadt2Y+lq4dKGcCVJzoZvPm1VKxD2y7xKa8/vEbPRiRTt0qnPq9T7UJkpDsiXf/zOMfWdjc3uA1bPnQ65RWHSJ7zAE+Gd7xnyCE5MEyijLE=</D> </RSAKeyValue> |
公钥:
1 2 3 4 |
<RSAKeyValue> <Modulus>pJlJIR0+G/vs7mhycs0Zd5DbWokMCsLX7Ih373+ljlteRmTm8IHj0Sl8zA26Qu/oAmqh9OFk806zW3TXl90RghSeQhzZBXFHBrTFN4U/o3wPhZBdFazh80bbskrmQ/jmz70qUm3HmGzsb3toxzN6Ehakdo7qP2Kc6aOVTyXrYpk=</Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> |
转换实现代码(c#) 格式转换要用到一个开源加密库Bouncy Castle Crypto APIs,官网地址: http://www.bouncycastle.org/csharp/ 具体实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
using System; using System.Xml; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; /// <summary> /// RSA密钥格式转换 /// </summary> public class RSAKeyConvert { /// <summary> /// RSA私钥格式转换,java->.net /// </summary> /// <param name="privateKey">java生成的RSA私钥</param> /// <returns></returns> public static string RSAPrivateKeyJava2DotNet(string privateKey) { RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)); return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>", Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())); } /// <summary> /// RSA私钥格式转换,.net->java /// </summary> /// <param name="privateKey">.net生成的私钥</param> /// <returns></returns> public static string RSAPrivateKeyDotNet2Java(string privateKey) { XmlDocument doc = new XmlDocument(); doc.LoadXml(privateKey); BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText)); BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText)); BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText)); BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText)); BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText)); BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText)); BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText)); BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText)); RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv); PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam); byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded(); return Convert.ToBase64String(serializedPrivateBytes); } /// <summary> /// RSA公钥格式转换,java->.net /// </summary> /// <param name="publicKey">java生成的公钥</param> /// <returns></returns> public static string RSAPublicKeyJava2DotNet(string publicKey) { RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey)); return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>", Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()), Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned())); } /// <summary> /// RSA公钥格式转换,.net->java /// </summary> /// <param name="publicKey">.net生成的公钥</param> /// <returns></returns> public static string RSAPublicKeyDotNet2Java(string publicKey) { XmlDocument doc = new XmlDocument(); doc.LoadXml(publicKey); BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText)); BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText)); RsaKeyParameters pub = new RsaKeyParameters(false, m, p); SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub); byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded(); return Convert.ToBase64String(serializedPublicBytes); } } |
from:https://www.cnblogs.com/datous/p/RSAKeyConvert.html
View Details