先理解一行代码
1 2
| @Resource Map<String, ProductService> ServiceMap = new ConcurrentHashMap<>(2);
|
此代码在 Spring Boot 启动时会被执行并创建一个 ConcurrentHashMap 实例, 以及它所引用的 ProductService 实现类的实例对象. 这些对象将被记录到map中
其中 String 就是 ProductService类的名字, 可以通过@Service(“serviceA”)来修改. 如果 ProductService 是一个接口. 那么 String 就是其对应的接口的名字.
实践一个简单的
- 编写 Controller 代码时, 经常遇到根据入参不同, 执行不同的 Service 逻辑的需求, 我们最常用的 if 来判断. 代码如下:
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
| @RestController public class ProductController { @Resource private ServiceOrderA serviceOrderA; @Resource private ServiceOrderB serviceOrderB;
@PostMapping("/order") public String order(@RequestParam(value = "type") String type) { if ("productA".equals(type)) { return serviceOrderA.orderingProduct(); } else if ("productB".equals(type)) { return serviceOrderB.orderingProduct();
}else { return "没有发现对应的产品处理策略"; } }
}
|
- 当 type 变多时, 需要注入很多的 private ServiceOrderA serviceOrderA; if 判断链也会很长. 代码杂乱没有章法, 且显得没有技术含量. 🙃
- 此时引入策略模式, 所有 Service 抽象成 ProductService
1 2 3
| public interface ProductService { String orderingProduct(); }
|
- 不同 Service 实现不同的 orderingProduct 逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Service("productA") public class ProductAServiceImpl implements ProductService { @Override public String orderingProduct() { return "成功订购产品A"; } }
@Service("productB") public class ProductBServiceImpl implements ProductService { @Override public String orderingProduct() { return "成功订购产品B"; } }
|
- 增加容器存放 Service
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Component public class InterfaceContainer {
@Resource Map<String, ProductService> configComponentMap = new ConcurrentHashMap<>(2);
public ProductService getProductStrategy(String productName) {
return configComponentMap.get(productName); }
}
|
- 简化 Controller
1 2 3 4 5 6 7
| @Resource private InterfaceContainer interfaceContainer; @PostMapping("/order1") public String order1(@RequestParam(value = "type") String type) { ProductService productService = interfaceContainer.getProductStrategy(type); return productService != null ? productService.orderingProduct() : "没有发现对应的产品处理策略"; }
|
再来一个实际运用
设计一个前后端分离系统, 会涉及到很多单表的通用操作, 比如都根据id查询明细, 都通过自定义参数查询, 查询表的总行数用于分页, 单表写入, 单表更新等接口.
每个单表服务都写一个 controller ? 可以但不够优雅.
我们依旧采用策略模式优化.
此类通用操作先抽象成接口 ICommonQuery. 增加一个管理类来处理接口调用逻辑 CommonQueryManager
每个服务分别实现接口, 完成自己的逻辑.
外部暴露一个 controller. 通过 @PathVariable 获取 url 的 apiname, 然后去 map 中获取 Service. 进而调用到对应的服务.
ICommonQuery
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
| public interface ICommonQuery {
Object selectOne(Long id) throws Exception;
List<?> select(Map<String, String> parameterMap) throws Exception;
Long counts(Map<String, String> parameterMap) throws Exception;
int insert(JSONObject obj, HttpServletRequest request) throws Exception;
int update(JSONObject obj, HttpServletRequest request) throws Exception;
int delete(Long id, HttpServletRequest request) throws Exception;
int deleteBatch(String ids, HttpServletRequest request) throws Exception;
int checkIsNameExist(Long id, String name) throws Exception; }
|
CommonQueryManager
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| @Service public class CommonQueryManager {
@Resource private InterfaceContainer container;
public Object selectOne(String apiName, Long id) throws Exception { if (StringUtils.isNotEmpty(apiName) && id!=null) { return container.getCommonQuery(apiName).selectOne(id); } return null; }
public List<?> select(String apiName, Map<String, String> parameterMap)throws Exception { if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).select(parameterMap); } return new ArrayList<Object>(); }
public Long counts(String apiName, Map<String, String> parameterMap)throws Exception { if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).counts(parameterMap); } return 0L; }
@Transactional(value = "transactionManager", rollbackFor = Exception.class) public int insert(String apiName, JSONObject obj, HttpServletRequest request) throws Exception{ if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).insert(obj, request); } return 0; }
@Transactional(value = "transactionManager", rollbackFor = Exception.class) public int update(String apiName, JSONObject obj, HttpServletRequest request)throws Exception { if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).update(obj, request); } return 0; }
@Transactional(value = "transactionManager", rollbackFor = Exception.class) public int delete(String apiName, Long id, HttpServletRequest request)throws Exception { if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).delete(id, request); } return 0; }
@Transactional(value = "transactionManager", rollbackFor = Exception.class) public int deleteBatch(String apiName, String ids, HttpServletRequest request)throws Exception { if (StringUtils.isNotEmpty(apiName)) { return container.getCommonQuery(apiName).deleteBatch(ids, request); } return 0; }
public int checkIsNameExist(String apiName, Long id, String name) throws Exception{ if (StringUtils.isNotEmpty(apiName) && name!=null) { return container.getCommonQuery(apiName).checkIsNameExist(id, name); } return 0; }
}
|
InterfaceContainer
1 2 3 4 5 6 7 8 9 10 11
| @Service public class InterfaceContainer { @Resource private final Map<String, ICommonQuery> configComponentMap = new ConcurrentHashMap<>();
public ICommonQuery getCommonQuery(String apiName) { return configComponentMap.get(apiName); } }
|
一个简单实现类
1 2 3 4 5 6 7 8
| @Service("ypxx") public class YPSerice implements ICommonQuery { @Override public Object selectOne(Long id) throws Exception { return "YPSerice - selectOne 调用成功了"; }
|
ResourceController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @RestController @Api(tags = {"资源接口-通用查询"}) public class ResourceController { @Resource CommonQueryManager commonQueryManager;
@GetMapping(value = "/{apiName}/info") @ApiOperation(value = "根据id获取信息") public Response info(@PathVariable("apiName") String apiName, @RequestParam("id") Long id, HttpServletRequest request) throws Exception { Map<String, Object> objectMap = new HashMap<String, Object>(); Object obj = commonQueryManager.selectOne(apiName, id); objectMap.put("info", obj); return Result.ok(objectMap); } }
|
效果如下