编辑
2023-06-28
JAVA
00

快试试用 API Key 来保护你的 SpringBoot 接口安全吧

5d677760bd80c2fe10d93765088b59ed.jpg

1、概述

安全性在REST API开发中扮演着重要的角色。一个不安全的REST API可以直接访问到后台系统中的敏感数据。因此,企业组织需要关注API安全性。

Spring Security 提供了各种机制来保护我们的 REST API。其中之一是 API 密钥。API 密钥是客户端在调用 API 调用时提供的令牌。

在本教程中,我们将讨论如何在Spring Security中实现基于API密钥的身份验证。

2、REST API Security

Spring Security可以用来保护REST API的安全性。REST API是无状态的,因此不应该使用会话或cookie。相反,应该使用Basic authentication,API Keys,JWT或OAuth2-based tokens来确保其安全性。

2.1. Basic Authentication

Basic authentication是一种简单的认证方案。客户端发送HTTP请求,其中包含Authorization标头的值为Basic base64_url编码的用户名:密码。Basic authentication仅在HTTPS / SSL等其他安全机制下才被认为是安全的。

2.2. OAuth2

OAuth2是REST API安全的行业标准。它是一种开放的认证和授权标准,允许资源所有者通过访问令牌将授权委托给客户端,以获得对私有数据的访问权限。

2.3. API Keys

一些REST API使用API密钥进行身份验证。API密钥是一个标记,用于向API客户端标识API,而无需引用实际用户。标记可以作为查询字符串或在请求头中发送。

3、用API Keys保护REST API

3.1 添加Maven 依赖

让我们首先在我们的pom.xml中声明spring-boot-starter-security依赖关系:

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

3.2 创建自定义过滤器(Filter)

实现思路是从请求头中获取API Key,然后使用我们的配置检查秘钥。在这种情况下,我们需要在Spring Security 配置类中添加一个自定义的Filter。

我们将从实现GenericFilterBean开始。GenericFilterBean是一个基于javax.servlet.Filter接口的简单Spring实现。

让我们创建AuthenticationFilter类:

public class AuthenticationFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { try { Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request); SecurityContextHolder.getContext().setAuthentication(authentication); } catch (Exception exp) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); PrintWriter writer = httpResponse.getWriter(); writer.print(exp.getMessage()); writer.flush(); writer.close(); } filterChain.doFilter(request, response); } }

我们只需要实现doFilter()方法,在这个方法中我们从请求头中获取API Key,并将生成的Authentication对象设置到当前的SecurityContext实例中。

然后请求被传递给其余的过滤器处理,接着转发给DispatcherServlet最后到达我们的控制器。

在AuthenticationService类中,实现从Header中获取API Key并构造Authentication对象,代码如下:

public class AuthenticationService { private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY"; private static final String AUTH_TOKEN = "Baeldung"; public static Authentication getAuthentication(HttpServletRequest request) { String apiKey = request.getHeader(AUTH_TOKEN_HEADER_NAME); if ((apiKey == null) || !apiKey.equals(AUTH_TOKEN)) { throw new BadCredentialsException("Invalid API Key"); } return new ApiKeyAuthentication(apiKey, AuthorityUtils.NO_AUTHORITIES); } }

在这里,我们检查请求头是否包含 API Key,如果为空 或者Key值不等于密钥,那么就抛出一个 BadCredentialsException。如果请求头包含 API Key,并且验证通过,则将密钥添加到安全上下文中,然后调用下一个安全过滤器。getAuthentication 方法非常简单,我们只是比较 API Key 头部和密钥是否相等。

为了构建 Authentication 对象,我们必须使用 Spring Security 为了标准身份验证而构建对象时使用的相同方法。所以,需要扩展 AbstractAuthenticationToken 类并手动触发身份验证。

3.3. 扩展AbstractAuthenticationToken

为了成功地实现我们应用的身份验证功能,我们需要将传入的API Key转换为AbstractAuthenticationToken类型的身份验证对象。AbstractAuthenticationToken类实现了Authentication接口,表示一个认证请求的主体和认证信息。

让我们创建ApiKeyAuthentication类:

public class ApiKeyAuthentication extends AbstractAuthenticationToken { private final String apiKey; public ApiKeyAuthentication(String apiKey, Collection<?extends GrantedAuthority> authorities) { super(authorities); this.apiKey = apiKey; setAuthenticated(true); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return apiKey; } }

ApiKeyAuthentication 类是类型为 AbstractAuthenticationToken 的对象,其中包含从 HTTP 请求中获取的 apiKey 信息。在构造方法中使用 setAuthenticated(true) 方法。因此,Authentication对象包含 apiKey 和authenticated字段:

977ca77dc6cc6ededff8f1510962f434.png

3.4. Security Config

通过创建建一个SecurityFilterChain bean,可以通过编程方式把我们上面编写的自定义过滤器(Filter)进行注册。

我们需要在 HttpSecurity 实例上使用 addFilterBefore() 方法在 UsernamePasswordAuthenticationFilter 类之前添加 AuthenticationFilter。

创建SecurityConfig 类:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf() .disable() .authorizeRequests() .antMatchers("/**") .authenticated() .and() .httpBasic() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }

此外注意代码中我们吧绘画策略(session policy)设置为无状态(STATELESS),因为我们使用的是REST。

3.5. ResourceController

最后,我们创建ResourceController,实现一个Get请求 /home

@RestController public class ResourceController { @GetMapping("/home") public String homeEndpoint() { return "Baeldung !"; } } 3.6. 禁用 Auto-Configuration @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class}) public class ApiKeySecretAuthApplication { public static void main(String[] args) { SpringApplication.run(ApiKeySecretAuthApplication.class, args); } }

4. 测试

我们先不提供API Key进行测试

curl --location --request GET 'http://localhost:8080/home'

返回 401 未经授权错误。

请求头中加上API Key后,再次请求

curl --location --request GET 'http://localhost:8080/home' \ --header 'X-API-KEY: Baeldung'

请求返回状态200

编辑
2023-06-27
中间件
00

Linux安装nginx详细步骤

一、安装nginx依赖

#centos #安装gcc yum install gcc-c++ #安装PCRE pcre-devel yum install -y pcre pcre-devel #安装zlib yum install -y zlib zlib-devel #安装Open SSL yum install -y openssl openssl-devel #ubuntu sudo apt update sudo apt-get install libpcre3-dev sudo apt-get install ruby sudo apt-get install zlib1g-dev

二、下载并解压nginx安装包

1.下载nginx安装包

wget http://nginx.org/download/nginx-1.23.0.tar.gz

你也可以到网站选择你所需要的版本

下载完成后将压缩包通过ssh命令使用winscp工具或其他工具上传至服务器

2.解压nginx安装包

#创建一个文件夹 cd /usr/local mkdir nginx cd nginx #解压缩包,直接tar -xvf nginx安装包所在路径 tar -xvf nginx-1.16.1.tar.gz

三、安装nginx

#进入nginx目录 cd /usr/local/nginx #进入目录 cd nginx-1.16.1 #编译 执行命令 考虑到后续安装ssl证书 添加两个模块 如不需要直接执行./configure即可 ./configure --with-http_stub_status_module --with-http_ssl_module #执行make命令(要是执行不成功请检查最开始安装的四个依赖有没有安装成功) make #执行make install命令 make install

补充查看编译参数

# 查看编译参数 ./configure --help | more

四、启动nginx

cd /usr/local/nginx/sbin # 默认配置文件启动 ./nginx # 指定配置文件启动 ./nginx -c /usr/local/nginx/conf/nginx.conf

五、停止重启nginx

cd /usr/local/nginx/sbin # 停止指令 ./nginx -s stop # 或 ./nginx -s quit # 重启命令 ./nginx -s reload # 查看nginx进程 ps -ef|grep nginx

六、设置开机自启动nginx

#编辑 vim /etc/rc.local #最底部增加这一行 /usr/local/nginx/sbin/nginx

七、补充

1.配置nginx.conf

若要修改监听端口,可打开nginx的配置文件进行修改。

# 打开配置文件 vi /usr/local/nginx/conf/nginx.conf

将端口号改成8089(随便挑个端口,你也可以修改为8848,等等)。

2.防火墙设置

若想使用外部主机访问nginx,上一步中若修改默认的80端口为8089,则需要关闭服务器防火墙或开放nginx服务端口。

centOS6及以前版本使用命令:

systemctl stop iptables.service

centOS7关闭防火墙命令:

systemctl stop firewalld.service #不过,关闭防火墙会导致服务器有一定风险,所以建议是单独开放服务端口: firewall-cmd --zone=public --add-port=8089/tcp --permanent #查询端口号8089 是否开启: firewall-cmd --query-port=8089/tcp #重启防火墙: firewall-cmd --reload # 查看firewall防火墙状态 systemctl status firewalld # 查看firewall防火墙开放端口 firewall-cmd --list-ports #禁止firewall开机启动 systemctl disable firewalld.service

apt方式安装nginx

卸载nginx

apt-get --purge autoremove nginx

指定版本安装nginx

apt-get update #查看有哪些版本 apt-cache show nginx #安装指定版本的nginx apt-get install nginx=1.18.0-6ubuntu14.4.1

目录说明

/usr/sbin/nginx:主程序,启动文件

/etc/nginx:存放配置文件

/var/www/html:存放项目目录

/var/log/nginx:存放日志

一般自动安装配置文件目录和主程序目录不变,因为版本原因,其它目录可能会变,但是都可以从配置文件里ngxin.conf里找到对应的位置。

nginx管理命令

service nginx start service nginx restart service nginx stop
编辑
2023-06-12
database
00

Mysql基本操作

连接MYSQL:

格式: mysql -h主机地址 -u用户名 -p用户密码

1、例1:连接到本机上的MYSQL

找到mysql的安装目录,一般可以直接键入命令mysql -uroot -p,回车后提示你输密码,如果刚安装好MYSQL,超级用户root是没有密码的,故直接回车即可进入到MYSQL中了,MYSQL的提示符是:mysql>

2、连接到远程主机上的MYSQL

假设远程主机的IP为:10.0.0.1,用户名为root,密码为123。则键入以下命令:

mysql -h10.0.0.1 -uroot -p123

(注:u与root可以不用加空格,其它也一样)

3、退出MYSQL命令

exit (回车)

修改密码

方法1: 用SET PASSWORD命令

首先登录MySQL。

格式:mysql> set password for 用户名@localhost = password(‘新密码’);

例子:mysql> set password for root@localhost = password(‘123’);

方法2:用mysqladmin

格式:mysqladmin -u用户名 -p旧密码 password 新密码

例子:mysqladmin -uroot -p123456 password 123

方法3:用UPDATE直接编辑user表

首先登录MySQL。

mysql> use mysql; mysql> update user set password=password(‘123’) where user=‘root’ and host=‘localhost’; mysql> flush privileges;

方法4:在忘记root密码的时候,可以这样

以windows为例:

关闭正在运行的MySQL服务。

打开DOS窗口,转到mysql\bin目录。

输入mysqld --skip-grant-tables 回车。–skip-grant-tables 的意思是启动MySQL服务的时候跳过权限表认证。

再开一个DOS窗口(因为刚才那个DOS窗口已经不能动了),转到mysql\bin目录。

输入mysql回车,如果成功,将出现MySQL提示符 >。

连接权限数据库: use mysql; 。

改密码:update user set password=password(“123”) where user=“root”;(别忘了最后加分号) 。

刷新权限(必须步骤):flush privileges; 。

退出 quit。

注销系统,再进入,使用用户名root和刚才设置的新密码123登录。

编辑
2023-06-06
docker
00

LDAP数据迁移同步

数据迁移

原始数据备份命令如下:

ldapsearch -LLL -x -h 218.97.51.117 -p 389 -D "cn=Admin,ou=Administrator,dc=cpccd,dc=com" -w Cpcnet\!\@\#\$\%\^ -b "dc=cpccd,dc=com" > openldap-backupfull.ldif

环境准备:

ubuntu安装docker:

更新ubuntu

sudo apt update sudo apt upgrade sudo apt full-upgrade

添加 Docker 库

sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release

添加 Docker 的官方 GPG 密钥

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

添加 Docker 官方库

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

更新 Ubuntu 源列表

sudo apt update

安装docker

sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

检查可以安装的docker版本

apt-cache madison docker-ce

安装最新的docker-ce

apt install docker-ce=5:24.0.1-1~ubuntu.22.04~jammy docker-ce-cli=5:24.0.1-1~ubuntu.22.04~jammy containerd.io

启动docker

sudo systemctl start docker

docker服务在每次启动时自动启动

sudo systemctl enable docker

查看docker版本

sudo docker version

docker compose部署openldap

docker-compose.yaml文件路径

/usr/local/docker/openldap2.0/docker-compose.yaml

docker-compose.yaml具体内容如下:

version: "3.7" services: openldap-bitnami: user: root image: bitnami/openldap:2.5.13 container_name: openldap1 volumes: - ./openldap-bitnami-data:/bitnami/openldap environment: - LDAP_ORGANISATION=CPC CD - LDAP_ROOT=dc=cpccd,dc=com - LDAP_ADMIN_USERNAME=admin - LDAP_ADMIN_PASSWORD=Cpcnet!@#$$%^ - LDAP_ULIMIT_MOFILES=107374182400 - LDAP_CONFIG_ADMIN_ENABLED=yes - LDAP_CONFIG_ADMIN_USERNAME=admin - LDAP_CONFIG_ADMIN_PASSWORD=admin - LDAP_ALLOW_ANON_BINDING=no - LDAP_USER_DC=people ports: - 1389:1389 - 1636:1636 networks: - openldap-bitnami networks: openldap-bitnami: name: openldap-bitnami

运行命令:

Docker-compose up –d

验证ldap容器是否创建成功命令如下:

ldapsearch -x -H ldap://localhost:389 -b 'dc=cpccd,dc=com' -D 'cn=admin,dc=cpccd,dc=com' -w 'Cpcnet!@#$%^'

为每一个openldap服务添加同步用的用户

需要使用管理账号登录,分别在所有节点导入以下配置。

syncrepl_user.ldif

version: 1 dn: uid=rpuser,ou=people,dc=demo,dc=com objectClass: top objectClass: person objectClass: organizationalPerson objectClass: simpleSecurityObject objectClass: shadowAccount objectClass: inetOrgPerson cn: rpuser sn: rpuser uid: rpuser userPassword: {SSHA}oBWZtlM7e3CbUagQeUPqkVeFUmg2+4liXvRfVQ==

用户dn:rpuser,ou=people,dc=demo,dc=com"

密码:rpuser

ldapmodify -a -x -H ldap://localhost:389 -D 'cn=admin,dc=cpccd,dc=com' -w 'Cpcnet!@#$%^' -f syncrepl_user.ldif

各节点同步文件

需要使用配置管理账号登录,在所有同步节点导入以下配置。

syncrepl_config.ldif

#enable syncprov module dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModulePath: /opt/bitnami/openldap/lib/openldap olcModuleLoad: syncprov.so #enable syncprov for every folder dn: olcOverlay=syncprov,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov olcSpSessionlog: 100 #unlimit fetch size dn: cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 10000 #set server id dn: cn=config changetype: modify replace: olcServerID olcServerID: 1 #syncrepl directive dn: olcDatabase={2}mdb,cn=config changetype: modify replace: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://需要同步的ip:389/ bindmethod=simple binddn="uid=rpuser,ou=people,dc=cpccd,dc=com" credentials=rpuser searchbase="dc=cpccd,dc=com" scope=sub schemachecking=on type=refreshAndPersist retry="5 +" interval=00:00:30:00 - add: olcMirrorMode olcMirrorMode: TRUE olcSyncRepl: rid=002 provider=ldap://需要同步的ip:389/ bindmethod=simple binddn="uid=rpuser,ou=people,dc=cpccd,dc=com" credentials=rpuser searchbase="dc=cpccd,dc=com" scope=sub schemachecking=on type=refreshAndPersist retry="5 +" interval=00:00:30:00 - add: olcMirrorMode olcMirrorMode: TRUE olcSyncRepl: rid=003 provider=ldap://需要同步的ip:389/ bindmethod=simple binddn="uid=rpuser,ou=people,dc=cpccd,dc=com" credentials=rpuser searchbase="dc=cpccd,dc=com" scope=sub schemachecking=on type=refreshAndPersist retry="5 +" interval=00:00:30:00 - add: olcMirrorMode olcMirrorMode: TRUE

该脚本设置了搜索的大小限制为10000,从dc=cpccd,dc=com搜索并同步数据,每30秒同步一次,失败会在5秒后重试。请根据实际的环境和项目要求进行修改。

ldapadd -Wx -D "cn=admin,cn=config" -H ldap://localhost:389 -f syncrepl_config.ldif

修改用户权限

需要使用配置管理账号登录,在所有节点分别导入以下配置。

db_config.ldif

dn: cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 10000 #db max size dn: olcDatabase={2}mdb,cn=config changeType: modify add: olcDbMaxSize olcDbMaxSize: 1000000000

执行以下命令:

ldapmodify -Wx -D "cn=admin,cn=config" -H ldap://localhost:389 -f db_config.ldif

选择任意一台ldap服务器进行数据导入:

ldapmodify -a -x -H ldap://localhost:389 -D 'cn=admin,dc=cpccd,dc=com' -w Cpcnet\!\@\#\$\%\^ -f openldap-backupfull.ldif -v -c

查看导入结果:

ldapsearch -x -H ldap://localhost:389 -b 'dc=cpccd,dc=com' -D 'cn=admin,ou=Administrator,dc=cpccd,dc=com' -w 'Cpcnet!@#$%^' 'mail=demo01@citictel-cpc.com'
编辑
2023-06-05
JAVA
00

前言

在开发中经常需要将json字符串转换为java对象或者list数组,这样方便我们来使用这些数据,下面就来介绍一下怎样将json字符串和json数组转换为Java对象或者list数组。

本次使用阿里巴巴的fastjson来解析json字符串,需要添加依赖:

<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.8</version> </dependency>

一、什么是JSON对象?

在大括号 {…} 中书写,包含多个 key/value(键/值)对,key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null) 例如一个最简单的没有嵌套的JSON对象:

{"name":"Sun", "age":18, "site":null}

二、什么是json字符串?

书写格式和JSON对象一样,不过类型属于String,不能直接操作其中的各个属性,需要对其进行转换。在很多前后端交互传值之类的,都以json字符串的形式进行传递。,所以对json字符串进行转换非常有必要。

二、什么是JSON数组?

JSON 数组在中括号中书写,JSON 中数组值必须是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。 简单的JSON数组:

["Google", "Runoob", "Taobao"]

三、复杂、嵌套的json字符串

复杂的是json字符串里面嵌套json数组,这也是转换的重点,例如:

{ "student": [ { "name": "Tom", "Grade": 1, "age": 11, "gender": "M" }, { "name": "Jerry", "Grade": 1, "age": 10, "gender": "M" } ], "classroom": { "class1": "room1", "class2": "room2" } }

在这里推荐几个比较好用的json字符串校验和格式化的网站:

链接: http://www.kjson.com/

链接: https://www.bejson.com/

四、json字符串转换

4.1 简单json字符串转换为java对象

转换语句:

//方法1 将json字符串转换为java对象 Student student =JSON.parseObject(jsonStr,Student .class); //方法2 先将json字符串转换成JSONObject对象 JSONObject jsonObject1 = new JSONObject(JSON.parseObject(jsonStr)); //将转换后的JSONObject对象转换成Student对象 Student student1 = (Student) JSONObject.toJavaObject(jsonObject1,Student.class); 示例:解析如下json字符串 { “name”: “Tom”, “Grade”: 1, “age”: 11, “gender”: “M” } 首先创建一个对应的对象: 1 public class Student { private String name; private int grade; private int age; private String gender; //省略get、set方法 } public void testJson(){ String jsonStr = "{\n" + " \"name\": \"Tom\", \n" + " \"Grade\": 1, \n" + " \"age\": 11, \n" + " \"gender\": \"M\"\n" + " }"; JSONObject jsonObject = new JSONObject(JSON.parseObject(jsonStr)); System.out.println("jsonObject:"+jsonObject); System.out.println("name:"+jsonObject.get("name")); System.out.println("Grade:"+jsonObject.get("Grade")); System.out.println("age:"+jsonObject.get("age")); //方法1 将json字符串转换为java对象 Student student =JSON.parseObject(jsonStr,Student .class); System.out.println("student:"+student); //方法2 先将json字符串转换成JSONObject对象 JSONObject jsonObject1 = new JSONObject(JSON.parseObject(jsonStr)); //将转换后的JSONObject对象转换成Student对象 Student student1 = (Student) JSONObject.toJavaObject(jsonObject1,Student.class); System.out.println("student1:"+student1); //转换为java对象之后可以利用对象的get方法来取值 System.out.println("age:"+student.getAge()); }

4.2 简单json字符串数组转换为list数组

使用语句:

List<Student> studentList = JSONObject.parseArray(jsonStr, Student.class); 示例: [ { “name”: “Tom”, “Grade”: 1, “age”: 11, “gender”: “M” }, { “name”: “Jerry”, “Grade”: 1, “age”: 10, “gender”: “M” } ] 首先创建一个对应的java对象: public class Student { private String name; private int grade; private int age; private String gender; //省略get、set方法 } public void testJson(){ String jsonStr = "[\n" + " {\n" + " \"name\": \"Tom\", \n" + " \"Grade\": 1, \n" + " \"age\": 11, \n" + " \"gender\": \"M\"\n" + " }, \n" + " {\n" + " \"name\": \"Jerry\", \n" + " \"Grade\": 1, \n" + " \"age\": 10, \n" + " \"gender\": \"M\"\n" + " }\n" + "]"; List<Student> studentList = JSONObject.parseArray(jsonStr, Student.class); System.out.println("studentList:"+studentList); for (int i = 0; i < studentList.size(); i++) { System.out.println("name:"+studentList.get(i).getName()); System.out.println("Grade:"+studentList.get(i).getGender()); System.out.println("age:"+studentList.get(i).getAge()); } }

4.3 复杂嵌套json字符串数组转换为Java对象、list数组

使用语句:

示例:

{ “student”: [ { “name”: “Tom”, “Grade”: 1, “age”: 11, “gender”: “M” }, { “name”: “Jerry”, “Grade”: 1, “age”: 10, “gender”: “M” } ], “classroom”: { “class1”: “fifth floor”, “class2”: “seventh floor” } } 首先创建对应的java对象,上面的Student对象可以重复使用,这里需要再添加两个对象,一个整体的包含Student和Classroom的对象School ,一个Classroom对象: public class School { //这里的Student和Classroom声明为Object类型 private Object Student; private Object Classroom; //省略get、set方法 } public class Classroom { private String class1; private String class2; //省略get、set方法 } 进行转换: public void testJson(){ String jsonStr = "{\n" + " \"student\": [\n" + " {\n" + " \"name\": \"Tom\", \n" + " \"Grade\": 1, \n" + " \"age\": 11, \n" + " \"gender\": \"M\"\n" + " }, \n" + " {\n" + " \"name\": \"Jerry\", \n" + " \"Grade\": 1, \n" + " \"age\": 10, \n" + " \"gender\": \"M\"\n" + " }\n" + " ], \n" + " \"classroom\": {\n" + " \"class1\": \"fifth floor\", \n" + " \"class2\": \"seventh floor\"\n" + " }\n" + "}"; //方法1 调用JSON.parseObject方法将json字符串转换为java对象 School school =JSON.parseObject(jsonStr,School.class); System.out.println("school:"+school); //方法2 先将json字符串转换成JSONObject对象 JSONObject jsonObject = new JSONObject(JSON.parseObject(jsonStr)); //将转换后的JSONObject对象整体转换成School对象 School school1 = (School) JSONObject.toJavaObject(jsonObject,School.class); System.out.println("school1:"+school1); //将School中的student数组转换成list对象 List<Student> studentList = JSONObject.parseArray(school.getStudent().toString(), Student.class); System.out.println("studentList:"+studentList); for (int i = 0; i < studentList.size(); i++) { System.out.print("name:"+studentList.get(i).getName()+","); System.out.print("Grade:"+studentList.get(i).getGender()+","); System.out.println("age:"+studentList.get(i).getAge()); } //将School中的classroom转换成java对象 与刚开始转换school的思路是一样的 //从school对象中getClassroom,返回的是一个Object对象类型 Object classroomObj = school.getClassroom(); //用toString()方法将Object对象转换成String String strClassroom = school.getClassroom().toString(); //方法1 调用JSON.parseObject方法将json字符串转换为java对象 Classroom classroom1 =JSON.parseObject(strClassroom,Classroom.class); System.out.println("classroom1:"+classroom1); //方法2 先将json字符串转换成JSONObject对象 JSONObject jsonClassroom = new JSONObject(JSON.parseObject(strClassroom)); //再利用JSONObject.toJavaObject转换为java对象 Classroom classroom2 = (Classroom) JSONObject.toJavaObject(jsonClassroom,Classroom.class); System.out.println("classroom2:"+classroom2); }

4.3.2 示例2

使用语句:

在4.3.1的基础上新增了两个字段:schoolName和address。Student对象和Classroom对象可以使用,需要重新创建一个整体的对象HighSchool

示例:

{ “schoolName”: “ECNU”, “address”: “Road”, “student”: [{ “name”: “Tom”, “Grade”: 1, “age”: 11, “gender”: “M” }, { “name”: “Jerry”, “Grade”: 1, “age”: 10, “gender”: “M” } ], “classroom”: { “class1”: “fifth floor”, “class2”: “seventh floor” } } 首先创建对应的java对象,上面的Student对象可以重复使用,这里需要再添加两个对象,一个整体的包含Student和Classroom的对象,一个Classroom对象: public class School { //这里的Student和Classroom声明为Object类型 private Object Student; private Object Classroom; //省略get、set方法 } public class Classroom { private String class1; private String class2; //省略get、set方法 } 进行转换: public void testJson(){ String jsonStr = "{\n" + " \"schoolName\": \"ECNU\", \n" + " \"address\": \"Road\", \n" + " \"student\": [\n" + " {\n" + " \"name\": \"Tom\", \n" + " \"Grade\": 1, \n" + " \"age\": 11, \n" + " \"gender\": \"M\"\n" + " }, \n" + " {\n" + " \"name\": \"Jerry\", \n" + " \"Grade\": 1, \n" + " \"age\": 10, \n" + " \"gender\": \"M\"\n" + " }\n" + " ], \n" + " \"classroom\": {\n" + " \"class1\": \"fifth floor\", \n" + " \"class2\": \"seventh floor\"\n" + " }\n" + "}"; //方法1 调用JSON.parseObject方法将json字符串转换为java对象 HighSchool highSchool = JSON.parseObject(jsonStr,HighSchool.class); System.out.println("highSchool:"+ highSchool); System.out.println("schoolName:"+ highSchool.getSchoolName()); System.out.println("address:"+ highSchool.getAddress()); //方法2 与之前讲过的一样,这里就省略掉了 //将School中的student数组转换成list对象 List<Student> studentList = JSONObject.parseArray(highSchool.getStudent().toString(), Student.class); System.out.println("studentList:"+studentList); for (int i = 0; i < studentList.size(); i++) { System.out.print("name:"+studentList.get(i).getName()+","); System.out.print("Grade:"+studentList.get(i).getGender()+","); System.out.println("age:"+studentList.get(i).getAge()); } //HighSchool 与刚开始转换school的思路是一样的 //从highSchool对象中getClassroom,返回的是一个Object对象类型 Object classroomObj = highSchool.getClassroom(); //用toString()方法将Object对象转换成String String strClassroom = highSchool.getClassroom().toString(); //方法1 调用JSON.parseObject方法将json字符串转换为java对象 Classroom classroom1 =JSON.parseObject(strClassroom,Classroom.class); System.out.println("classroom1:"+classroom1); //方法2 与之前讲过的一样,这里就省略掉了 }

总结

转换大体上分为两种:

1、以{……}大括号包裹的数据要转换为java对象;

2、 以[ ] 中括号包裹的数据转换为list数组。

首先要明白,以 { } 开头的是JSONObject,以 [ ] 开头的是JSONArray,如果本身就是json字符串的格式(即格式类型为String),那就不用转换,直接使用转换方法进行转换。

但是如果是嵌套字符串的话,从第一次转换后的java对象中取出来的是Object类型,这时候需要先用toString方法转换为String类型,然后再调用方法。