WEB层是最终表现层,注册至注册中心,引用接口层(不需要引用实现层)、公共服务层。用户登录使用SpringSecurity,Session保存在redis中,权限管理没有用SpringSecurity那套,自己写了一个简单的菜单、按钮权限控制。我在虚拟机192.168.0.7中搭了一个redis服务。
一、redis搭建
下载redis后,在linux下启动比较简单。需要注意的是redis.config配置:
1. 如果想配置用户名密码
requirepass 123456
2. 如果不bind IP地址,默认只能本机访问
bind 192.168.0.7
写一个批处理startredis.sh,启动redis
./redis-5.0.7/src/redis-server ./redis-5.0.7/redis.conf
二、WEB层主要依赖包
<!--依赖系统管理相关接口工程,供Feign调用,减少冗余代码--> <dependency> <groupId>com.zyproject</groupId> <artifactId>zyproject-api-service-system</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
<!-- 公共类工程--> <dependency> <groupId>com.zyproject</groupId> <artifactId>zyproject-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
<!-- redis,需要注意的是引入commons-pool2,否则会报错 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>2.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
<!--引入feign,远程调用Service服务--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.1.RELEASE</version> </dependency> <!--整合freemarker--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!--依赖系统管理相关接口工程--> <dependency> <groupId>com.zyproject</groupId> <artifactId>zyproject-api-service-system</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--spring secrity--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.1.4.RELEASE</version> </dependency>
三、FeignClient通用接口
创建一个接口,继承自接口层ISystemService,这样就可以直接使用Feign实现RPC调用接口实现层暴露出来的http服务了。
package com.zyproject.web.feignclient; import com.zyproject.service.ISystemService; import org.springframework.cloud.openfeign.FeignClient; /** * @program: zyproject * @description: RPC调用系统管理相关接口服务 * @author: zhouyu(zhouyu629 # qq.com) * @create: 2020-02-11 **/ @FeignClient("zyproject-api-service-system") //注意这里,对应的是接口实现层在注册中心的别名。我这个别名取的有点问题,跟接口层不一样,不合适。 public interface SystemFeign extends ISystemService { }
然后建立一个Service包,里面调用这个Feign接口,最后Controller调用Service即可。以UserService为例:
package com.zyproject.web.service; import com.zyproject.common.ResponseData; import com.zyproject.web.feignclient.SystemFeign; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestParam; /** * @program: zyproject * @description: 用户服务 * @author: zhouyu(zhouyu629 # qq.com) * @create: 2020-02-11 **/ @Service public class UserService { @Autowired private SystemFeign systemFeign; //用户登录 public ResponseData userLogin(@RequestParam String user_code, @RequestParam String password){ return systemFeign.userLogin(user_code,password); } //根据登录名,获取用户信息 public ResponseData findByLoginname(String login_name){ return systemFeign.findByLoginname(login_name); } }
有个细节需要注意:
Feign直接调用接口实现RPC,这使得远程调用简单了很多,传递参数可以是一些Java类型,比如传Entity、List、Map等对象。最终底层应该是HttpClient,默认会报错,但可以解决。
但从实际应用角度出发,不建议这样做,向外暴露的http接口,理论上也可以提供给其他应用程序使用,其他开发语言调用,不能限制死是java类型,建议是通过gson或fastjson,将这些类型转换为json字符串进行http参数传递,实现侧再转换回java类型。下面是一个例子:
客户端请求:
/** * 设置角色权限 * @param role_id * @param tree_ids:考虑到对其他语言的兼容性,不建议传java类型 * @param btn_ids:考虑到对其他语言的兼容性,不建议传java类型 * @return */ public ResponseData setRoleRight(@RequestParam int role_id, @RequestParam(name = "tree_ids",required = true) String tree_ids, @RequestParam(name = "btn_ids",required = true) String btn_ids){ return systemFeign.setRoleRight(role_id,tree_ids,btn_ids); } /** * 新增或编辑角色 * @param roleEntity:角色信息,Feign前转换为json字符串 * @return */ public ResponseData addOrUpdateRole(RoleEntity roleEntity){ String role = new Gson().toJson(roleEntity); return this.systemFeign.addOrUpdateRole(role); }
服务端接收(类型转换,应该做容错判断,代码里没有做):
@PostMapping("/setRoleRight") @ApiOperation("设置角色权限") @ApiImplicitParams({ @ApiImplicitParam(name = "role_id",value = "角色ID",dataType = "int"), @ApiImplicitParam(name = "tree_ids", value = "选中的菜单",dataType = "String"), @ApiImplicitParam(name = "btni_ds",value = "选中的按钮",dataType = "String") }) @Override @Transactional public ResponseData setRoleRight(int role_id, String tree_ids,String btn_ids) { Gson gson = new Gson(); List<String> tree = gson.fromJson(tree_ids,new TypeToken<List<String>>(){}.getType()); List<Map<String,String>> btn = gson.fromJson(btn_ids,new TypeToken<List<Map<String,String>>>(){}.getType()); boolean result = this.roleDao.setRoleRight(role_id,tree,btn); return ResponseData.out(result?CodeEnum.SUCCESS:CodeEnum.FAIL,null); } @GetMapping("/addOrUpdateRole") @ApiOperation("新增或修改角色") @ApiImplicitParams( @ApiImplicitParam(name = "role",value = "角色实体json字符串") ) @Override public ResponseData addOrUpdateRole(String role) { //将role转换为实体类 boolean result = this.roleDao.addOrUpdateRole(new Gson().fromJson(role,RoleEntity.class)); return ResponseData.out(result?CodeEnum.SUCCESS:CodeEnum.FAIL,null); }
四、SpringSecurity集成
待续
五、FreeMarker集成
待续
六、权限管理
待续