SpringBoot04_分模块开发实例
copy注水预警:这篇博客很水
一、结构介绍
由于这部分代码比较多,建的文件也比较多,所以选择直接上传到了 gitee 的 仓库 中,提交更新也是一步步来的,应该会比博客更清晰。
分别创建三个模块,每个模块都有自己的数据库和端口号,模块之间通过 resthttp 的方式调用。
还是老几样,common 包里放的是三个模块对应的 POJO 和 工具类,工具类主要就是控制返回值的,让其返回一个我们写好的返回方式。
以 user-service 包为例,还是访问 URL 先到 Controller 里面,Controller 在调用相应 Service 的方法,Service 调用 Dao 层也就是 Mapper 的方法,这里没有直接采用注解在 Mapper 方法上面写 SQL 而是采用了传统的 xm 文件方式。
(一)通用模块
主要存放的是三个数据库表对应的实体类,为了更更好模拟实际中的网络请求情况所以自定义了返回类型和处理返回值的工具类。关于返回值处理的具体细节大家阅读源码。
copy//订单信息
package com.purearc.modules.common.pojo;
@Data
@Accessors(chain = true)
public class OrdersInfo {
private Long id;
private Long productId;
private Long productCount;
private Long userId;
private Date createTime;
private Date updateTime;
}
//产品
@Data
@Accessors(chain = true)
public class Product {
private Long id;
private String productName;
private Double price;
private Date createTime;
private Date updateTime;
}
//用户实体
@Data
@Accessors(chain = true)
public class SysUser {
private Long userId;
private String userName;
private String realName;
private String userPass;
private Date birthday;
private String address;
private Date createTime;
private Date updateTime;
}
定义的返回值泛型类以及枚举类
copypackage com.purearc.modules.common.vo;
//泛型
@Data
@Accessors(chain = true)
public class LangsinResult<T> {
private Integer code;
private String msg;
private T data;
}
public enum LangsinResultEnum {
NOT_LOGIN_CODE(403, "没有登录"),
SUCCESS_CODE(200, "成功"),
FAILED_CODE(202, "失败");
private Integer code;
private String msg;
//枚举类
LangsinResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
(二)Service 模块简述
将 Controll=er 、Service 和 Mapper 都放到容器中管理,需要时通过注解形式注入。前端发送的请求通过转发进入到 Controller 中,Controller 找到对应的 Service 方法,Service 中在对 Mapper 数据持久层进行调用,Mapper 文件对应的方法在 XML 文件中,也可以选择注解写 SQL 语句。
其他模块的和这个差不多
copyserver:
port: 7777
servlet:
context-path: /userService
#连接数据库
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/users_dbcharacterEncoding=UTF8&useSSL=false&useUnicode=true&serverTimezone=UTC
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
#config-location:
mapper-locations: classpath:mybatis/*Mapper.xml
#设置字段对应
configuration:
map-underscore-to-camel-case: true
在 SpringBoot 的核心配置文件中,主要更改了服务的端口号、context-path、mybatis 中实体与数据表的对应和 Mapper.xml 所在的
位置,在 product-service 和 order-service 中也是类似的结构。
代码比较多所以截取三层调用的部分,也没什么难的。
二、users-service
copy/**
* 访问时传入一个 ID
* 调用 Service 的 getById 方法
* 注入 service 来调用 service 中的方法
*/
package com.purearc.modules.users.controller.SysUserController
@RestController
@RequestMapping("/sysUser")
public class SysUserController {
@Autowired
private SysUserService userService;
@RequestMapping("/getById")
public LangsinResult getById(Long id) {
return LangsinResultUtil.success(userService.getById(id));
}
}
/**
* Service 中定义 getById 方法
*/
import com.purearc.modules.common.pojo.SysUser;
public interface SysUserService {
SysUser getById(Long id);
}
/**
* 实现 getById
*/
package com.purearc.modules.users.service.impl;
@Service
public class SysUserServiceImpl implements SysUserService {
@Autowired
private SysUserMapper sysUserMapper;
@Override
public SysUser getById(Long id) {
return sysUserMapper.findById(id);
}
}
/**
* mapper.xml 文件就不写了,也没什么可说的
*/
package com.purearc.modules.users.mapper;
@Mapper
public interface SysUserMapper {
// @Select("select user_id,user_name,real_name,user_pass,birthday,address,create_time,update_time from sys_user where user_id = #{id}")
SysUser findById(Long id);
}
三、product-service
没什么好说的,简单测试了一下能用
copy/**
* date: 2023/5/25
*
* @author Arc
*/
package com.purearc.modules.product.controller;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping("/getById")
public LangsinResult gtById(Long id) {
// Product arrayList = productService.getById(id);
// System.out.println(arrayList);
return LangsinResultUtil.success(productService.getById(id));
}
}
//————————————————————————————————————————————————————————————————————————————
import com.purearc.modules.common.pojo.Product;
import com.purearc.modules.common.vo.LangsinResultEnum;
public interface ProductService {
Product getById(Long id);
}
//————————————————————————————————————————————————————————————————————————————
package com.purearc.modules.product.service.impl;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Override
public Product getById(Long id) {
return productMapper.selectByPrimaryKey(id);
}
}
//————————————————————————————————————————————————————————————————————————————
package com.purearc.modules.product.mapper;
@Mapper
public interface ProductMapper {
@Select("select id,product_name,price,create_time,update_time from product where id = #{id}")
int updateByPrimaryKey(Product record);
}
四、order-service
在 order 我们想在查询订单信息的时候也能查询到 product-service 和 users- service 中的数据表获得他们的数据,所以我们在 Service 就要返回两个服务中数据表的组合体,自然就要首先自定义个返回的类型它里面既要有 User 的属性也要有 Product 的属性,我们在 common 模块中的 pojo 已经定义过 OrdersInfo 所以我们可以定义一个 OrderInfoVo 来继承这个类,我们就可以通过 get 方法获得其中的属性,变相继承了这个类中的属性。
copypackage com.purearc.modules.order.vo;
@Data
@Accessors(chain = true)
public class OrderInfoVo extends OrdersInfo {
/**
* 用户属性
*/
private String userName;
private String realName;
private String userPass;
private Date birthday;
private String address;
/**
* 商品属性
*/
private String productName;
private Double price;
private Double count;
}
Controller,里面就一个 list 方法,也就是查询所有订单的信息。
copypackage com.purearc.modules.order.controller;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("/list")
public LangsinResult list(){
return LangsinResultUtil.success(orderService.list());
}
}
我们自然是应该把发送 http 请求的任务交给 service:在查询出所有的 order 后我们通过order 中的 userId 和 productId 查询 user 的相关属性和 product 的相关属性,然后将两个属性封装成一个整体返回。
copy注意点:
1、使用的 CollectionUtil 是 cn-hutool 包中的判断查询的订单 list 是否 null,否则 return。
2、List<OrderInfoVo> 用于接收最后的封装结果返回
3、Map<String,Object> params 用于使用 Http.post 时间传入参数。
copypackage com.purearc.modules.order.service;
public interface OrderService {
List<OrderInfoVo> list();
}
//-----------------------------------------------------------------
package com.purearc.modules.order.service.impl;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrdersInfoMapper ordersInfoMapper;
@Override
public List<OrderInfoVo> list() {
List<OrdersInfo> ordersInfos = ordersInfoMapper.list();
if(CollectionUtil.isEmpty(ordersInfos)){
return null;
}
List<OrderInfoVo> orderInfoVoList = new ArrayList<>();
Map<String,Object> params = new HashMap<>();
for (OrdersInfo ordersInfo : ordersInfos) {
Long userId = ordersInfo.getUserId();
//调用用户模块查询用户信息
params.put("id",userId);
String userInfoStr = HttpUtil.post("http://localhost:7777/userService/sysUser/getById",params);
LangsinResult userInfo = JSONUtil.toBean(userInfoStr, LangsinResult.class);
// System.out.println(userInfo);
Long productId = ordersInfo.getProductId();
//调用商品模块 查询商品信息
params.put("id",productId);
String productInfoStr = HttpUtil.post("http://localhost:9999/productService/product/getById",params);
LangsinResult productInfo = JSONUtil.toBean(productInfoStr, LangsinResult.class);
// System.out.println(productInfo.getClass());
//封装成为一个新的对象OrderInfoVo
OrderInfoVo temp = new OrderInfoVo();
BeanUtils.copyProperties(userInfo,temp);
BeanUtils.copyProperties(productInfo,temp);
System.out.println(temp);
orderInfoVoList.add(temp);
}
return orderInfoVoList;
}
}
我们使用 postman 模拟访问 "/order/list" 并将根据 userId 和 productId 获得的 user 与 product 打印出来。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端