[javase][json]fastJson在java后台转换json格式数据探究--处理数组/List/Map

本文介绍使用 FastJSON 库将 Java 对象如数组、列表和 Map 转换为 JSON 格式字符串的方法,并展示了如何反向操作,即将 JSON 字符串转换回 Java 对象。

原文地址:http://blog.youkuaiyun.com/hu_shengyang/article/details/8447787


直接给代码:

[java]  view plain copy
  1. package fastJson.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import com.alibaba.fastjson.JSON;  
  9. import com.alibaba.fastjson.JSONArray;  
  10.   
  11. public class FastJsonTest1  
  12. {  
  13.   
  14.     /** 
  15.      * 数组转json格式字符串 
  16.      */  
  17.     public void array2Json(){  
  18.         String[] arr = {"bill","green","maks","jim"};  
  19.         String jsonText = JSON.toJSONString(arr, true);  
  20.         System.out.println("array2Json()方法:jsonText=="+jsonText);  
  21.         // 输出结果:jsonText==["bill","green","maks","jim"]  
  22.     }  
  23.   
  24.     /** 
  25.      * json格式字符串转数组 
  26.      */  
  27.     public void json2Array(){  
  28.         String jsonText = "[\"bill\",\"green\",\"maks\",\"jim\"]";  
  29.         JSONArray jsonArr = JSON.parseArray(jsonText);  
  30.         System.out.println("json2Array()方法:jsonArr=="+jsonArr);  
  31.         // 输出结果:jsonArr==["bill","green","maks","jim"]  
  32.     }  
  33.       
  34.     /** 
  35.      * 数组转json格式字符串 
  36.      */  
  37.     public void array2Json2(){  
  38.         User user1 = new User("P001","TOM",16);  
  39.         User user2 = new User("P002","JACKSON",21);  
  40.         User user3 = new User("P003","MARTIN",20);  
  41.         User[] userArr = {user1,user2,user3};  
  42.         String jsonText = JSON.toJSONString(userArr, true);  
  43.         System.out.println("array2Json2()方法:jsonText=="+jsonText);  
  44.         //输出结果:jsonText==[{"age":16,"id":"P001","name":"TOM"},{"age":21,"id":"P002","name":"JACKSON"},{"age":20,"id":"P003","name":"MARTIN"}]  
  45.     }  
  46.       
  47.     /** 
  48.      * json格式字符串转数组 
  49.      */  
  50.     public void json2Array2(){  
  51.         String jsonText = "[{\"age\":16,\"id\":\"P001\",\"name\":\"TOM\"},{\"age\":21,\"id\":\"P002\",\"name\":\"JACKSON\"},{\"age\":20,\"id\":\"P003\",\"name\":\"MARTIN\"}]";  
  52.         JSONArray jsonArr = JSON.parseArray(jsonText);  
  53.         System.out.println("json2Array2()方法:jsonArr=="+jsonArr);  
  54.         // 输出结果:jsonArr==[{"age":16,"id":"P001","name":"TOM"},{"age":21,"id":"P002","name":"JACKSON"},{"age":20,"id":"P003","name":"MARTIN"}]  
  55.     }  
  56.       
  57.     /** 
  58.      * list集合转json格式字符串 
  59.      */  
  60.     public void list2Json(){  
  61.         List list = new ArrayList();  
  62.         User user1 = new User("L001","TOM",16);  
  63.         list.add(user1);  
  64.         User user2 = new User("L002","JACKSON",21);  
  65.         list.add(user2);  
  66.         User user3 = new User("L003","MARTIN",20);  
  67.         list.add(user3);  
  68.         String jsonText = JSON.toJSONString(list, true);  
  69.         System.out.println("list2Json()方法:jsonText=="+jsonText);  
  70.         //输出结果:jsonText==[{"age":16,"id":"L001","name":"TOM"},{"age":21,"id":"L002","name":"JACKSON"},{"age":20,"id":"L003","name":"MARTIN"}]  
  71.     }  
  72.       
  73.     /** 
  74.      * list集合转json格式字符串 
  75.      */  
  76.     public void list2Json2(){  
  77.         List list = new ArrayList();  
  78.         Address address1 = new Address("广东省","深圳市","科苑南路","580053");  
  79.         User user1 = new User("L001","TOM",16,address1);  
  80.         list.add(user1);  
  81.         Address address2 = new Address("江西省","南昌市","阳明路","330004");  
  82.         User user2 = new User("L002","JACKSON",21,address2);  
  83.         list.add(user2);  
  84.         Address address3 = new Address("陕西省","西安市","长安南路","710114");  
  85.         User user3 = new User("L003","MARTIN",20,address3);  
  86.         list.add(user3);  
  87.         String jsonText = JSON.toJSONString(list, true);  
  88.         System.out.println("list2Json2()方法:jsonText=="+jsonText);  
  89.         //输出结果:jsonText==[{"address":{"city":"深圳市","post":"580053","province":"广东省","street":"科苑南路"},"age":16,"id":"L001","name":"TOM"},{"address":{"city":"南昌市","post":"330004","province":"江西省","street":"阳明路"},"age":21,"id":"L002","name":"JACKSON"},{"address":{"city":"西安市","post":"710114","province":"陕西省","street":"长安南路"},"age":20,"id":"L003","name":"MARTIN"}]  
  90.     }  
  91.   
  92.     /** 
  93.      * map转json格式字符串 
  94.      */  
  95.     public void map2Json(){  
  96.         Map map = new HashMap();  
  97.         Address address1 = new Address("广东省","深圳市","科苑南路","580053");  
  98.         map.put("address1", address1);  
  99.         Address address2 = new Address("江西省","南昌市","阳明路","330004");  
  100.         map.put("address2", address2);  
  101.         Address address3 = new Address("陕西省","西安市","长安南路","710114");  
  102.         map.put("address3", address3);  
  103.         String jsonText = JSON.toJSONString(map, true);  
  104.         System.out.println("map2Json()方法:jsonText=="+jsonText);  
  105.         //输出结果:jsonText=={"address1":{"city":"深圳市","post":"580053","province":"广东省","street":"科苑南路"},"address2":{"city":"南昌市","post":"330004","province":"江西省","street":"阳明路"},"address3":{"city":"西安市","post":"710114","province":"陕西省","street":"长安南路"}}  
  106.     }  
  107.       
  108.       
  109.       
  110.     public static void main(String[] args)  
  111.     {  
  112.         FastJsonTest1 test = new FastJsonTest1();  
  113.         //数组转json格式字符串  
  114.         test.array2Json();  
  115.           
  116.         //json格式字符串转数组  
  117.         test.json2Array();  
  118.           
  119.         //数组转json格式字符串  
  120.         test.array2Json2();  
  121.           
  122.         //json格式字符串转数组  
  123.         test.json2Array2();  
  124.           
  125.         //list集合转json格式字符串  
  126.         test.list2Json();  
  127.           
  128.         //list集合转json格式字符串  
  129.         test.list2Json2();  
  130.           
  131.         //map转json格式字符串  
  132.         test.map2Json();  
  133.     }  
  134. }  

控制台输出结果:

[html]  view plain copy
  1. array2Json()方法:jsonText==["bill","green","maks","jim"]  
  2. json2Array()方法:jsonArr==["bill","green","maks","jim"]  
  3. array2Json2()方法:jsonText==[{  
  4.     "age":16,  
  5.     "id":"P001",  
  6.     "name":"TOM"  
  7. },{  
  8.     "age":21,  
  9.     "id":"P002",  
  10.     "name":"JACKSON"  
  11. },{  
  12.     "age":20,  
  13.     "id":"P003",  
  14.     "name":"MARTIN"  
  15. }]  
  16. json2Array2()方法:jsonArr==[{"age":16,"id":"P001","name":"TOM"},{"age":21,"id":"P002","name":"JACKSON"},{"age":20,"id":"P003","name":"MARTIN"}]  
  17. list2Json()方法:jsonText==[  
  18.     {  
  19.         "age":16,  
  20.         "id":"L001",  
  21.         "name":"TOM"  
  22.     },  
  23.     {  
  24.         "age":21,  
  25.         "id":"L002",  
  26.         "name":"JACKSON"  
  27.     },  
  28.     {  
  29.         "age":20,  
  30.         "id":"L003",  
  31.         "name":"MARTIN"  
  32.     }  
  33. ]  
  34. list2Json2()方法:jsonText==[  
  35.     {  
  36.         "address":{  
  37.             "city":"深圳市",  
  38.             "post":"580053",  
  39.             "province":"广东省",  
  40.             "street":"科苑南路"  
  41.         },  
  42.         "age":16,  
  43.         "id":"L001",  
  44.         "name":"TOM"  
  45.     },  
  46.     {  
  47.         "address":{  
  48.             "city":"南昌市",  
  49.             "post":"330004",  
  50.             "province":"江西省",  
  51.             "street":"阳明路"  
  52.         },  
  53.         "age":21,  
  54.         "id":"L002",  
  55.         "name":"JACKSON"  
  56.     },  
  57.     {  
  58.         "address":{  
  59.             "city":"西安市",  
  60.             "post":"710114",  
  61.             "province":"陕西省",  
  62.             "street":"长安南路"  
  63.         },  
  64.         "age":20,  
  65.         "id":"L003",  
  66.         "name":"MARTIN"  
  67.     }  
  68. ]  
  69. map2Json()方法:jsonText=={"address1":{  
  70.     "city":"深圳市",  
  71.     "post":"580053",  
  72.     "province":"广东省",  
  73.     "street":"科苑南路"  
  74. },"address2":{  
  75.     "city":"南昌市",  
  76.     "post":"330004",  
  77.     "province":"江西省",  
  78.     "street":"阳明路"  
  79. },"address3":{  
  80.     "city":"西安市",  
  81.     "post":"710114",  
  82.     "province":"陕西省",  
  83.     "street":"长安南路"  
  84. }}  


附:javabean类 User.java

[java]  view plain copy
  1. package fastJson.test;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class User implements Serializable {  
  6.       
  7.     private static final long serialVersionUID = 1L;  
  8.       
  9.     private String id;  
  10.     private String name;  
  11.     private int age;  
  12.     private Address address;  
  13.       
  14.     public User() {  
  15.         super();  
  16.     }  
  17.   
  18.     public User(String id, String name, int age) {  
  19.         super();  
  20.         this.id = id;  
  21.         this.name = name;  
  22.         this.age = age;  
  23.     }  
  24.       
  25.     public User(String id, String name, int age, Address address)  
  26.     {  
  27.         super();  
  28.         this.id = id;  
  29.         this.name = name;  
  30.         this.age = age;  
  31.         this.address = address;  
  32.     }  
  33.   
  34.     public int getAge() {  
  35.         return age;  
  36.     }  
  37.   
  38.     public void setAge(int age) {  
  39.         this.age = age;  
  40.     }  
  41.   
  42.     public String getId() {  
  43.         return id;  
  44.     }  
  45.   
  46.     public void setId(String id) {  
  47.         this.id = id;  
  48.     }  
  49.   
  50.     public String getName() {  
  51.         return name;  
  52.     }  
  53.   
  54.     public void setName(String name) {  
  55.         this.name = name;  
  56.     }  
  57.   
  58.     public Address getAddress()  
  59.     {  
  60.         return address;  
  61.     }  
  62.   
  63.     public void setAddress(Address address)  
  64.     {  
  65.         this.address = address;  
  66.     }  
  67.       
  68. }  

Address.java

[java]  view plain copy
  1. package fastJson.test;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class Address implements Serializable  
  6. {  
  7.     private static final long serialVersionUID = 1L;  
  8.       
  9.     private String province;  
  10.     private String city;  
  11.     private String street;  
  12.     private String post;  
  13.       
  14.     public Address()  
  15.     {  
  16.         super();  
  17.     }  
  18.       
  19.     public Address(String province, String city, String street, String post)  
  20.     {  
  21.         super();  
  22.         this.province = province;  
  23.         this.city = city;  
  24.         this.street = street;  
  25.         this.post = post;  
  26.     }  
  27.   
  28.     public String getCity()  
  29.     {  
  30.         return city;  
  31.     }  
  32.   
  33.     public void setCity(String city)  
  34.     {  
  35.         this.city = city;  
  36.     }  
  37.   
  38.     public String getPost()  
  39.     {  
  40.         return post;  
  41.     }  
  42.   
  43.     public void setPost(String post)  
  44.     {  
  45.         this.post = post;  
  46.     }  
  47.   
  48.     public String getProvince()  
  49.     {  
  50.         return province;  
  51.     }  
  52.   
  53.     public void setProvince(String province)  
  54.     {  
  55.         this.province = province;  
  56.     }  
  57.   
  58.     public String getStreet()  
  59.     {  
  60.         return street;  
  61.     }  
  62.   
  63.     public void setStreet(String street)  
  64.     {  
  65.         this.street = street;  
  66.     }  
  67.       
  68. }  
任务描述 本关任务:编写登录接口完成用户登录。 相关知识 为了完成本关任务,你需要了解:1.安全框架Apache Shiro,2.如何配置Shiro框架,3,如何编写登录接口。 安全框架Apache Shiro Apache Shiro 是一个功能强大且易于使用的 Java 安全框架,它为开发人员提供了一个直观而全面的身份验证、授权、加密和会话管理解决方案。不仅可以用在JavaSE环境,也可以用在JavaEE环境,可以完成:认证、授权、加密、会话管理、与Web集成、缓存等。如下是它具有的特点: ​ 1,易于理解的Java Security API; ​ 2,简单的身份认证(登录),支持多种数据源(LDAP、JDBC、Kerberos, ActiveDirectory等); ​ 3,对角色的简单的签权(访问控制),支持细粒度的签权; ​ 4,支持一级缓存,以提升应用程序的性能; ​ 5,内置的基于POJO企业会话管理,适用于Web以及非Web的环境; ​ 6,异构客户端会话访问; ​ 7,非常简单的加密API; ​ 8,不跟任何框架或者容器捆绑,可以独立运行。 Spring Security与Shiro的不同点: ​ 1:Spring Security基于Spring开发,项目中如果使用Spring作为基础,配合Spring Security做权限更加方便,而Shiro需要和Spring进行整合开发 ​ 2:Spring Security功能比Shiro更加丰富些,例如安全防护 ​ 3:Spring Security社区资源比Shiro丰富。 但是Shiro的配置和使用比较简单,依赖性低,Spring Security上手复杂,所以本项目使用Shiro框架。 Shiro架构 Shiro架构分为三个部分,如下: Subject:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject。Subject 代表了当前“用户”, 这个用户不一定 是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫, 机器人等;与 Subject 的所有交互都会委托给 SecurityManager; Subject 其实是一个门面,SecurityManager 才是实际的执行者; SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且其管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与 Shiro 的其他组件进行交互,它相当于 SpringMVC 中 DispatcherServlet 的角色。 Realm:Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户 进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色/ 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource。 如何配置Shiro框架 首先添加maven依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> 新建一个角色类,主要包括角色id、角色名称、角色代码。 package net.educoder.ims.pojo; import java.io.Serializable; /** * 角色实体类 * @author admin * @date 2021-07-19 */ public class Role implements Serializable { /** * 角色表id */ private Integer rid; /** * 角色名称 */ private String rname; /** * 角色代码 */ private String rcode; private static final long serialVersionUID = 1L; public Integer getRid() { return rid; } public void setRid(Integer rid) { this.rid = rid; } public String getRname() { return rname; } public void setRname(String rname) { this.rname = rname == null ? null : rname.trim(); } public String getRcode() { return rcode; } public void setRcode(String rcode) { this.rcode = rcode == null ? null : rcode.trim(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" ["); sb.append("Hash = ").append(hashCode()); sb.append(", rid=").append(rid); sb.append(", rname=").append(rname); sb.append(", rcode=").append(rcode); sb.append(", serialVersionUID=").append(serialVersionUID); sb.append("]"); return sb.toString(); } @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null) { return false; } if (getClass() != that.getClass()) { return false; } Role other = (Role) that; return (this.getRid() == null ? other.getRid() == null : this.getRid().equals(other.getRid())) && (this.getRname() == null ? other.getRname() == null : this.getRname().equals(other.getRname())) && (this.getRcode() == null ? other.getRcode() == null : this.getRcode().equals(other.getRcode())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getRid() == null) ? 0 : getRid().hashCode()); result = prime * result + ((getRname() == null) ? 0 : getRname().hashCode()); result = prime * result + ((getRcode() == null) ? 0 : getRcode().hashCode()); return result; } } 新建一个权限实体类,包括权限名称以及资源标识,代码类似。 新建一个UserRealm继承自AuthorizingRealm,实现我们的认证和授权逻辑。由于我们使用了state标识用户身份,而且我们需要根据不同的身份去不同的表查询相应的数据库,所以我们自定义了UsernamePasswordToken继承org.apache.shiro.authc.UsernamePasswordToken,在其中加入了state字段。 /** * @author Jason * @create 2021-07-19 9:11 */ public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; /** * 清除缓存 */ public void clearCache() { PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); super.clearCache(principals); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = usernamePasswordToken.getUsername(); int state = usernamePasswordToken.getState(); if (state == StateEnums.ADMIN.getCode()) { Admin admin = userService.getAdminByUsername(username); if (admin == null || admin.getAdmin() == 0) { throw new ImsException(ResultEnum.ERROR.getCode(), "账号异常!"); } return new SimpleAuthenticationInfo(admin, admin.getPassword(), this.getName()); } else { if (state == 1) { Student stu = userService.getStuByUsername(username); if (stu == null || stu.getStatus() == -1) { throw new ImsException(ResultEnum.ERROR.getCode(), "账号异常!"); } return new SimpleAuthenticationInfo(stu, stu.getPassword(), this.getName()); } Teacher teacher = userService.getTeacherByUsername(username); if (teacher == null || teacher.getStatus() == -1) { throw new ImsException(ResultEnum.ERROR.getCode(), "账号异常!"); } return new SimpleAuthenticationInfo(teacher, teacher.getPassword(), this.getName()); } } } 首先要配置的是ShiroConfig类,Apache Shiro 核心通过 Filter 来实现,就好像 SpringMVC 通过 DispachServlet 来主控制一样。既然是使用 Filter 一般也就能猜到,是通过 URL 规则来进行过滤和权限校验,所以我们需要定义一系列关于 URL 的规则和访问权限。 package net.educoder.ims.config; import com.google.common.collect.Maps; import net.educoder.ims.filters.LoginFilter; import net.educoder.ims.realm.UserRealm; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import javax.servlet.Filter; import java.util.Map; /** * shiro配置类 * @author admin */ @Configuration public class ShiroConfig { /** * 创建ShiroFilterFactoryBean */ @Bean("shiroFilterFactoryBean") public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { // 设置安全管理器 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 把自定义的过滤器放入shiro中 Map<String, Filter> shiroFilters = shiroFilterFactoryBean.getFilters(); /** * 常用过滤器 * anon:无需认证可以访问 * authc:必须认证才能访问 * user:如果使用rememberMe的功能可以直接访问 * perms:该资源必须得到权限才可以访问 * role:该资源必须得到角色权限才可以访问 */ Map<String, String> filterMap = Maps.newHashMap(); filterMap.put("/user/login", "anon"); filterMap.put("/user/logout", "logout"); filterMap.put("/*/register", "anon"); filterMap.put("/swagger-ui.html", "anon"); filterMap.put("/druid", "anon"); filterMap.put("/*/*/springfox.js", "anon"); filterMap.put("/swagger-resources/**", "anon"); filterMap.put("/webjars/springfox-swagger-ui/**", "anon"); filterMap.put("/v2/api-docs", "anon"); filterMap.put("/actuator/**", "roles[admin]"); filterMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } @Bean(name="sessionManager") public DefaultWebSessionManager defaultWebSessionManager() { ShiroSessionManager shiroSessionManager = new ShiroSessionManager(); shiroSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO()); return shiroSessionManager; } /** * 创建DefaultSecurityManager */ @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联realm securityManager.setRealm(userRealm); securityManager.setSessionManager(defaultWebSessionManager()); securityManager.setCacheManager(ehCacheManager()); return securityManager; } /** * 创建Realm */ @Bean public UserRealm userRealm() { UserRealm userRealm = new UserRealm(); userRealm.setCachingEnabled(true); // 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false userRealm.setAuthenticationCachingEnabled(true); // 缓存AuthenticationInfo信息的缓存名称 在 ehcache-shiro.xml 中有对应缓存的配置 userRealm.setAuthenticationCacheName("authenticationCache"); // 启用授权缓存,即缓存AuthorizationInfo信息,默认false userRealm.setAuthorizationCachingEnabled(true); // 缓存AuthorizationInfo 信息的缓存名称 在 ehcache-shiro.xml 中有对应缓存的配置 userRealm.setAuthorizationCacheName("authorizationCache"); return userRealm; } @Bean public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean @DependsOn("lifecycleBeanPostProcessor") public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } /** * 开启shiro aop注解支持. * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * shiro缓存管理器; * 需要添加到securityManager中 * @return */ @Bean public EhCacheManager ehCacheManager(){ EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return cacheManager; } } 为了防止用户未经登录就访问其它页面以及跨域等问题,我们还需要自定义登录拦截器: package net.educoder.ims.filters; import com.alibaba.fastjson.JSONObject; import net.educoder.ims.enums.ResultEnum; import net.educoder.ims.utils.Result; import org.apache.shiro.web.filter.authc.UserFilter; import org.apache.shiro.web.util.WebUtils; 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; /** * 登录拦截器 * @author admin */ public class LoginFilter extends UserFilter { /** * 这个方法用于处理未登录时页面重定向的逻辑 * 因此,只要进入了这个方法,就意味着登录失效了 * 我们只需要在这个方法里,给前端返回一个登录失效的状态码即可 * @param request * @param response * @throws IOException */ @Override protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException { response.setContentType("application/json; charset=utf-8"); response.getWriter().write(JSONObject.toJSONString(new Result<>(ResultEnum.NOT_LOGIN))); } /** * 解决复杂请求跨域 如预处理跨域问题 * @param request * @param response * @return * @throws Exception */ @Override 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-Origin", httpRequest.getHeader("Origin")); httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod()); httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers")); httpResponse.setStatus(HttpStatus.OK.value()); return true; } return super.preHandle(request, response); } /** * 解决OPTIONS请求被拦截问题 * @param request * @param response * @param mappedValue * @return */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { String method = "OPTIONS"; if (request instanceof HttpServletRequest) { if (method.equals(((HttpServletRequest) request).getMethod().toUpperCase())) { HttpServletResponse httpResp = WebUtils.toHttp(response); httpResp.setStatus(HttpStatus.OK.value()); return true; } } return super.isAccessAllowed(request, response, mappedValue); } } 然后需要在ShiroConfig.java的ShiroFilterFactoryBean中放置自定义的过滤器: // 把自定义的过滤器放入shiro中 Map<String, Filter> shiroFilters = shiroFilterFactoryBean.getFilters(); shiroFilters.put("authc", new LoginFilter()); 最后,我们自定义session获取方式,如果在Cookie中存在的话就取出sessionId,否则去请求头中寻找Authorization。 package net.educoder.ims.config; import net.educoder.ims.utils.StringUtils; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable; import java.util.Enumeration; /** * 自定义session获取方式 * 采用ajax请求头authToken携带sessionId的方式 * @author Jason * @create 2021-08-06 15:44 */ public class ShiroSessionManager extends DefaultWebSessionManager { private static final String AUTHORIZATION = "Authorization"; private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request"; public ShiroSessionManager() { super(); } @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { Enumeration<String> headers = WebUtils.toHttp(request).getHeaderNames(); String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION); if (StringUtils.isEmpty(id)) { //如果没有携带id参数则按照父类的方式在cookie进行获取 return super.getSessionId(request, response); } else { //如果请求头中有 Authorization 则其值为sessionId request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return id; } } } 如何编写登录接口 在这里我们遵循自定义的规则,用户名长度为12的用户代表学生,管理名称前缀都有admin,首先我们在controller层中编写一个/login的post接口,并判断传入的参数是否为空: @PostMapping(value = "/login") public Result<Object> login(@RequestBody UserVO user) { // 用户名长度为12 表示学生 final int codeLength = 12; // 管理员名称前缀 final String adminCode = "admin"; // 管理员前缀长度 final int adminCodeLength = 5; UserVO userVO = new UserVO(); Set<Permission> permissionSet = new HashSet(); Set<Role> roleSet = new HashSet(); if (user == null || StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) { return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误!"); } return null; } 然后我们通过SecurityUtils工具类从线程上下文中拿到subject,然后调用subjuect.login()实现登录,并获取sessionId作为token返回前端。 /** * 用户登录 * @param user * @return */ @ApiOperation(value = "登录接口",httpMethod = "POST",notes = "用户名,密码,必填") @ApiImplicitParams({@ApiImplicitParam(name="user",value="用户对象",dataType="UserVO",paramType = "body",required = false)}) @PostMapping(value = "/login") public Result<Object> login(@RequestBody UserVO user) { // 用户名长度为12 表示学生 final int codeLength = 12; // 管理员名称前缀 final String adminCode = "admin"; // 管理员前缀长度 final int adminCodeLength = 5; UserVO userVO = new UserVO(); Set<Permission> permissionSet = new HashSet(); Set<Role> roleSet = new HashSet(); if (user == null || StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) { return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误!"); } Subject subject = SecurityUtils.getSubject(); if (user.getUsername().length() >= adminCodeLength && user.getUsername().substring(0,adminCodeLength).equals(adminCode)) { user.setStatus(0); } else if (user.getUsername().length() == codeLength) { user.setStatus(1); } else { user.setStatus(2); } AuthenticationToken authenticationToken = new UsernamePasswordToken(user.getUsername(), user.getPassword(),user.getStatus()); try { subject.login(authenticationToken); } catch (Exception e) { return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误!"); } // 登录成功 Serializable sessionId = subject.getSession().getId(); try { Admin admin = (Admin) subject.getPrincipal(); userVO.setStatus(0); BeanUtils.copyProperties(admin,userVO); } catch (ClassCastException e) { BeanUtils.copyProperties(subject.getPrincipal(),userVO); } List<String> roleList = roleService.findRoleById(userVO.getId(), userVO.getStatus()); roleList.forEach(rid -> { roleSet.add(roleService.findById(Integer.valueOf(rid))); permissionSet.addAll(permissionService.findPermissionsByRid(Integer.valueOf(rid))); }); userVO.setPassword(""); Map<String, Object> returnMap = new HashMap<>(2); returnMap.put("token", sessionId); returnMap.put("user", userVO); returnMap.put("roleList", roleSet); returnMap.put("permissionList", permissionSet); return new Result<>(returnMap); } 编程要求 请仔细阅读右侧代码,结合相关知识,让我们编写一个用户登录接口,在Begin-End区域内进行代码补充: 完成ShiroConfig相关代码; 在UserController增加前端请求接口,设置请求地址为/login。 测试说明 平台会对你的代码进行运行测试,如果实际输出与预期输出只有header不一致,则算通关。另外,由于本关项目文件较大,评测时间较长,请同学们耐心等待!package net.educoder.ims.controller; import net.educoder.ims.enums.ResultEnum; import net.educoder.ims.enums.StateEnums; import net.educoder.ims.exception.ImsException; import net.educoder.ims.pojo.*; import net.educoder.ims.service.PermissionService; import net.educoder.ims.service.RoleService; import net.educoder.ims.service.UserService; import net.educoder.ims.token.UsernamePasswordToken; import net.educoder.ims.utils.IdWorker; import net.educoder.ims.utils.Page; import net.educoder.ims.utils.Result; import net.educoder.ims.utils.StringUtils; import net.educoder.ims.vo.UserVO; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.subject.Subject; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.io.Serializable; import java.util.*; /** * 用户公用接口 * @author Jason * @create 2021-07-19 9:55 */ @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; /** * 用户登录 * @param user * @return */ /****************** Begin ******************/ @PostMapping(value = "/login") public Result<Object> login(@RequestBody UserVO user) { // 用户名长度为12 表示学生 final int codeLength = 12; // 管理员名称前缀 final String adminCode = "admin"; // 管理员前缀长度 final int adminCodeLength = 5; UserVO userVO = new UserVO(); Set<Permission> permissionSet = new HashSet(); Set<Role> roleSet = new HashSet(); if (user == null || StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) { return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误!"); } Subject subject = SecurityUtils.getSubject(); // 补充代码,根据名称长度判断用户身份 // 补充代码,使用自定义的UsernamePasswordToken生成token AuthenticationToken authenticationToken = new UsernamePasswordToken(user.getUsername(), user.getPassword(),user.getStatus()); try { // 补充代码,调用subject.login并传入AuthenticationToken } catch (Exception e) { return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误!"); } // 登录成功 Serializable sessionId = subject.getSession().getId(); try { Admin admin = (Admin) subject.getPrincipal(); userVO.setStatus(0); BeanUtils.copyProperties(admin,userVO); } catch (ClassCastException e) { BeanUtils.copyProperties(subject.getPrincipal(),userVO); } List<String> roleList = roleService.findRoleById(userVO.getId(), userVO.getStatus()); roleList.forEach(rid -> { roleSet.add(roleService.findById(Integer.valueOf(rid))); permissionSet.addAll(permissionService.findPermissionsByRid(Integer.valueOf(rid))); }); userVO.setPassword(""); Map<String, Object> returnMap = new HashMap<>(2); returnMap.put("token", sessionId); returnMap.put("user", userVO); returnMap.put("roleList", roleSet); returnMap.put("permissionList", permissionSet); return new Result<>(returnMap); } /****************** End ******************/ }
最新发布
12-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值