在写完了用户模块之后, 接下来的选择就是账本模块与账户模块. 考虑到账本模块中需要将
AccountId也就是账户模块的id作为外键, 做级联删除处理, 因此选择先写账户模块
首先贴一下做的数据库联系图.
可以看到. Book表中包含了accountId与userId, 而userId在之前的用户模块中已经写完. 因此接下来决定写账户模块.
在确定了数据库表的设计之后, 那就是相对应的Account类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Account {
public static String UNKNOWN_MESSAGE = "查询账户不存在";
private Long id;
private String name;
private Long userId;
private Double balance;
}
id: 账户的id作为主键. 之后将作为Book表的外键, 此处按下不表name: 账户名.userId: 顾名思义, 该账户绑定的User用户. 考虑当一个用户注销时, 此账户也会相应删除. 因此需要做级联删除的外键绑定处理.balance: 账户余额
在确定了相应的类的设计之后, 与之前02中的mybatis设计相同, 之后进行dao的实现
首先是基础的增删改查操作:
@Mapper
public interface AccountDao {
Integer saveAccount(@Param("account") Account account);
Integer updateAccountById(@Param("account") Account account);
Integer deleteAccount(@Param("id") Long id);
Account getAccountById(@Param("id") Long id);
List<Account> getAccountsByUserId(@Param("userId") Long userId);
}
其中额外的getAccountsByUserId则是根据实际情况添加的根据用户Id找出所有账户, 毕竟一个用户可能, 或者说大概率不会只有一个账户. 因此就需要这样的一个接口获取该用户的所有账户信息.
在设计了dao后自然是需要对应的mapper将其实现.
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bngel.bngelbookaccountprovider8003.dao.AccountDao">
<insert id="saveAccount">
insert into bngel_account(name, user_id, balance) values (#{account.name}, #{account.userId}, #{account.balance});
</insert>
<delete id="deleteAccount">
delete from bngel_account where id = #{id};
</delete>
<select id="getAccountById" resultType="cn.bngel.bngelbookaccountprovider8003.bean.Account">
select * from bngel_account where id = #{id};
</select>
<update id="updateAccountById">
update bngel_account
<set>
<if test="account.name != null">`name`=#{account.name},</if>
<if test="account.userId != null">`user_id`=#{account.userId},</if>
<if test="account.balance != null">`balance`=#{account.balance}</if>
</set>
where `id` = #{account.id};
</update>
<select id="getAccountsByUserId" resultType="cn.bngel.bngelbookaccountprovider8003.bean.Account">
select * from bngel_account where user_id = #{userId};
</select>
</mapper>
sql代码与之前文章02中的大差不差, 则不再赘述.
相关动态SQL的使用可以参见:
[从零开始的账本项目02]
准备了dao且实现了mapper的匹配之后, 就可以创建service类进行使用.
一样是作为接口类service以及对应的impl实现类进行对应逻辑的实现.
由于偷懒就直接使用了dao中的方法, 并没有进行进一步的细分封装.
public interface AccountService {
Integer saveAccount(Account account);
Integer updateAccountById(Account account);
Integer deleteAccount(Long id);
Account getAccountById(Long id);
List<Account> getAccountsByUserId(Long userId);
}
之后通过@Autowire将之前写好的dao进行注入.
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Override
public Integer saveAccount(Account account) {
return accountDao.saveAccount(account);
}
@Override
public Integer updateAccountById(Account account) {
return accountDao.updateAccountById(account);
}
@Override
public Integer deleteAccount(Long id) {
return accountDao.deleteAccount(id);
}
@Override
public Account getAccountById(Long id) {
return accountDao.getAccountById(id);
}
@Override
public List<Account> getAccountsByUserId(Long userId) {
return accountDao.getAccountsByUserId(userId);
}
}
此处之前一直有一个错误. 就是习惯将接口类的service上标注@Service.
应该要在对应的Impl实现类中进行标注. 将实现的类存入Spring的容器中才对.
在Impl实现类中, 基本上只需要对应的返回即可.
之后的Controller类也基本上与用户模块的相同.
贴上一版没有加Knife4j和Slf4j的比较干净的代码.
@RestController
@Slf4j
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/account")
public CommonResult saveAccount(@RequestBody Account account) {
Integer result = accountService.saveAccount(account);
if (result == 1) {
return CommonResult.commonSuccessResult();
}
else {
return CommonResult.commonFailureResult();
}
}
@DeleteMapping("/account")
public CommonResult deleteAccountById(@RequestParam("id") Long id) {
Integer result = accountService.deleteAccount(id);
if (result >= 1) {
return CommonResult.commonSuccessResult();
}
else {
return CommonResult.commonFailureResult();
}
}
@PutMapping("/account")
public CommonResult updateAccountById(@RequestBody Account account) {
Integer result = accountService.updateAccountById(account);
if (result >= 1) {
return CommonResult.commonSuccessResult();
}
else {
return CommonResult.commonFailureResult();
}
}
@GetMapping("/account")
public CommonResult getAccountById(@RequestParam("id") Long id) {
Account account = accountService.getAccountById(id);
if (account != null) {
return new CommonResult(CommonResult.SUCCESS_CODE, account, CommonResult.SUCCESS_MESSAGE);
}
else {
return new CommonResult(CommonResult.FAILURE_CODE, Account.UNKNOWN_MESSAGE);
}
}
@GetMapping("/account/{userId}")
public CommonResult getAccountsByUserId(@PathVariable("userId") Long userId) {
List<Account> results = accountService.getAccountsByUserId(userId);
if (results != null) {
return new CommonResult(CommonResult.SUCCESS_CODE, results, CommonResult.SUCCESS_MESSAGE);
}
else {
return CommonResult.commonFailureResult();
}
}
}
与用户模块其实差别不大. 其中最需要注意的应该就是关于用户注销时, 账户的级联删除.
关于账本模块与账户之间的级联关系应该在下一篇的账本模块里也会提到.
欢迎各位来对我的小项目提出各种宝贵的意见, 这对我的进步非常重要, 谢谢大家.
GitHub地址: Bngel/bngelbook