商品进销存管理系统、ERP系统源码

  • 2021-04-06
  • Admin

【实例简介】

采用SpringBoot、HTML、JqueryUI、mysql实现的一整套进销存ERP系统,功能比较齐全,能立刻部署运行支持普通公司的ERP运营,附带测试使用的数据库,后管默认登录账号:admin 密码:123456

文件:590m.com/f/25127180-488778732-3b5ac3(访问密码:551685)

【实例截图】

在这里插入图片描述
在这里插入图片描述
【核心代码】

package com.jsh.erp.controller; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.jsh.erp.constants.BusinessConstants; import com.jsh.erp.constants.ExceptionConstants; import com.jsh.erp.datasource.entities.Account; import com.jsh.erp.datasource.vo.AccountVo4InOutList; import com.jsh.erp.exception.BusinessRunTimeException; import com.jsh.erp.service.account.AccountService; import com.jsh.erp.utils.BaseResponseInfo; import com.jsh.erp.utils.ErpInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.jsh.erp.utils.ResponseJsonUtil.returnJson; /** * @author jishenghua 752718920 / @RestController @RequestMapping(value = “/account”) public class AccountController { private Logger logger = LoggerFactory.getLogger(AccountController.class); @Resource private AccountService accountService; /* * 查找结算账户信息-下拉框 * @param request * @return / @GetMapping(value = “/findBySelect”) public String findBySelect(HttpServletRequest request) throws Exception {
String res = null; try {
List dataList = accountService.findBySelect(); //存放数据json数组 JSONArray dataArray = new JSONArray(); if (null != dataList) { for (Account account : dataList) {
JSONObject item = new JSONObject();
item.put(“Id”, account.getId()); //结算账户名称 item.put(“AccountName”, account.getName());
dataArray.add(item);
}
}
res = dataArray.toJSONString();
} catch(Exception e){
e.printStackTrace();
res = “获取数据失败”;
} return res;
} /
* * 获取所有结算账户 * @param request * @return / @GetMapping(value = “/getAccount”) public BaseResponseInfo getAccount(HttpServletRequest request) throws Exception {
BaseResponseInfo res = new BaseResponseInfo();
Map map = new HashMap(); try {
List accountList = accountService.getAccount();
map.put(“accountList”, accountList);
res.code = 200;
res.data = map;
} catch(Exception e){
e.printStackTrace();
res.code = 500;
res.data = “获取数据失败”;
} return res;
} /
* * 账户流水信息 * @param currentPage * @param pageSize * @param accountId * @param initialAmount * @param request * @return / @GetMapping(value = “/findAccountInOutList”) public BaseResponseInfo findAccountInOutList(@RequestParam(“currentPage”) Integer currentPage, @RequestParam(“pageSize”) Integer pageSize, @RequestParam(“accountId”) Long accountId, @RequestParam(“initialAmount”) BigDecimal initialAmount,
HttpServletRequest request) throws Exception{
BaseResponseInfo res = new BaseResponseInfo();
Map map = new HashMap(); try {
List dataList = accountService.findAccountInOutList(accountId, (currentPage-1)pageSize, pageSize); int total = accountService.findAccountInOutListCount(accountId);
map.put(“total”, total); //存放数据json数组 JSONArray dataArray = new JSONArray(); if (null != dataList) { for (AccountVo4InOutList aEx : dataList) {
String timeStr = aEx.getOperTime().toString();
BigDecimal balance = accountService.getAccountSum(accountId, timeStr, “date”).add(accountService.getAccountSumByHead(accountId, timeStr, “date”))
.add(accountService.getAccountSumByDetail(accountId, timeStr, “date”)).add(accountService.getManyAccountSum(accountId, timeStr, “date”)).add(initialAmount);
aEx.setBalance(balance);
dataArray.add(aEx);
}
}
map.put(“rows”, dataArray);
res.code = 200;
res.data = map;
} catch(Exception e){
e.printStackTrace();
res.code = 500;
res.data = “获取数据失败”;
} return res;
} @PostMapping(value = “/updateAmountIsDefault”) public String updateAmountIsDefault(@RequestParam(“isDefault”) Boolean isDefault, @RequestParam(“accountId”) Long accountId,
HttpServletRequest request) throws Exception{
Map objectMap = new HashMap(); int res = accountService.updateAmountIsDefault(isDefault, accountId); if(res > 0) { return returnJson(objectMap, ErpInfo.OK.name, ErpInfo.OK.code);
} else { return returnJson(objectMap, ErpInfo.ERROR.name, ErpInfo.ERROR.code);
}
} /
* create by: qiankunpingtai * website:https://qiankunpingtai.cn * description: * 批量删除账户信息 * create time: 2019/3/29 10:49 * @Param: ids * @return java.lang.Object */ @RequestMapping(value = “/batchDeleteAccountByIds”) public Object batchDeleteAccountByIds(@RequestParam(“ids”) String ids,@RequestParam(value=“deleteType”,
required =false,defaultValue=BusinessConstants.DELETE_TYPE_NORMAL)String deleteType) throws Exception {undefined

    JSONObject result = ExceptionConstants.standardSuccess(); /**  * create by: qiankunpingtai  * create time: 2019/4/10 10:19  * website:https://qiankunpingtai.cn  * description:  * 出于兼容性考虑,没有传递删除类型时,默认为正常删除  */  int i=0; if(BusinessConstants.DELETE_TYPE_NORMAL.equals(deleteType)){
         i= accountService.batchDeleteAccountByIdsNormal(ids);
    }else if(BusinessConstants.DELETE_TYPE_FORCE.equals(deleteType)){
         i= accountService.batchDeleteAccountByIds(ids);
    }else{ logger.error("异常码[{}],异常提示[{}],参数,ids[{}],deleteType[{}]",
                ExceptionConstants.DELETE_REFUSED_CODE,ExceptionConstants.DELETE_REFUSED_MSG,ids,deleteType); throw new BusinessRunTimeException(ExceptionConstants.DELETE_REFUSED_CODE,
                ExceptionConstants.DELETE_REFUSED_MSG);
    } if(i<1){ logger.error("异常码[{}],异常提示[{}],参数,ids[{}]",
                ExceptionConstants.ACCOUNT_DELETE_FAILED_CODE,ExceptionConstants.ACCOUNT_DELETE_FAILED_MSG,ids); throw new BusinessRunTimeException(ExceptionConstants.ACCOUNT_DELETE_FAILED_CODE,
                ExceptionConstants.ACCOUNT_DELETE_FAILED_MSG);
    } return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

}

package com.jsh.erp.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.jsh.erp.constants.BusinessConstants; import com.jsh.erp.constants.ExceptionConstants; import com.jsh.erp.datasource.entities.Tenant; import com.jsh.erp.datasource.entities.User; import com.jsh.erp.datasource.entities.UserEx; import com.jsh.erp.datasource.vo.TreeNodeEx; import com.jsh.erp.exception.BusinessParamCheckingException; import com.jsh.erp.service.log.LogService; import com.jsh.erp.service.tenant.TenantService; import com.jsh.erp.service.user.UserService; import com.jsh.erp.utils.; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.net.URLEncoder; import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static com.jsh.erp.utils.ResponseJsonUtil.returnJson; /** * @author ji_sheng_hua 华夏erp */ @RestController @RequestMapping(value = “/user”) public class UserController { private Logger logger = LoggerFactory.getLogger(UserController.class); @Value("${manage.roleId}") private Integer manageRoleId; @Resource private UserService userService; @Resource private TenantService tenantService; @Resource private LogService logService; private static String message = “成功”; private static final String HTTP = “http://”; private static final String CODE_OK = “200”;

@PostMapping(value = "/login") public BaseResponseInfo login(@RequestParam(value = "loginame", required = false) String loginame,
                    @RequestParam(value = "password", required = false) String password,
                    HttpServletRequest request)throws Exception {
    logger.info("============用户登录 login 方法调用开始==============");
    String msgTip = "";
    User user=null;
    BaseResponseInfo res = new BaseResponseInfo(); try {
        String username = loginame.trim();
        password = password.trim(); //判断用户是否已经登录过,登录过不再处理  Object userInfo = request.getSession().getAttribute("user");
        User sessionUser = new User(); if (userInfo != null) {
            sessionUser = (User) userInfo;
        } if (sessionUser != null && username.equalsIgnoreCase(sessionUser.getLoginame())) {
            logger.info("====用户 "  username "已经登录过, login 方法调用结束====");
            msgTip = "user already login";
        } //获取用户状态  int userStatus = -1; try {
            userStatus = userService.validateUser(username, password);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(">>>>>>>>>>>>>用户 "  username " 登录 login 方法 访问服务层异常====", e);
            msgTip = "access service exception";
        } switch (userStatus) { case ExceptionCodeConstants.UserExceptionCode.USER_NOT_EXIST:
                msgTip = "user is not exist"; break; case ExceptionCodeConstants.UserExceptionCode.USER_PASSWORD_ERROR:
                msgTip = "user password error"; break; case ExceptionCodeConstants.UserExceptionCode.BLACK_USER:
                msgTip = "user is black"; break; case ExceptionCodeConstants.UserExceptionCode.USER_ACCESS_EXCEPTION:
                msgTip = "access service error"; break; default: try {
                    msgTip = "user can login"; //验证通过 ,可以登录,放入session,记录登录日志  user = userService.getUserByUserName(username);
                    request.getSession().setAttribute("user",user); if(user.getTenantId()!=null) {
                        Tenant tenant = tenantService.getTenantByTenantId(user.getTenantId()); if(tenant!=null) {
                            Long tenantId = tenant.getTenantId();
                            Integer userNumLimit = tenant.getUserNumLimit();
                            Integer billsNumLimit = tenant.getBillsNumLimit(); if(tenantId!=null) {
                                request.getSession().setAttribute("tenantId",tenantId); //租户tenantId  request.getSession().setAttribute("userNumLimit",userNumLimit); //用户限制数  request.getSession().setAttribute("billsNumLimit",billsNumLimit); //单据限制数  }
                        }
                    }
                    logService.insertLog("用户", new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_LOGIN).append(user.getId()).toString(),
                            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error(">>>>>>>>>>>>>>>查询用户名为:"  username " ,用户信息异常", e);
                } break;
        }
        Map data = new HashMap();
        data.put("msgTip", msgTip); /**  * 在IE模式下,无法获取到user数据,  * 在此处明确添加上user信息  * */  if(user!=null){
            data.put("user",user);
        }
        res.code = 200;
        res.data = data;
        logger.info("===============用户登录 login 方法调用结束===============");
    } catch(Exception e){
        e.printStackTrace();
        logger.error(e.getMessage());
        res.code = 500;
        res.data = "用户登录失败";
    } return res;
}

@GetMapping(value = "/getUserSession") public BaseResponseInfo getSessionUser(HttpServletRequest request)throws Exception {
    BaseResponseInfo res = new BaseResponseInfo(); try {
        Map data = new HashMap();
        Object userInfo = request.getSession().getAttribute("user"); if(userInfo!=null) {
            User user = (User) userInfo;
            user.setPassword(null);
            data.put("user", user);
        }
        res.code = 200;
        res.data = data;
    } catch(Exception e){
        e.printStackTrace();
        res.code = 500;
        res.data = "获取session失败";
    } return res;
}

@GetMapping(value = "/logout") public BaseResponseInfo logout(HttpServletRequest request, HttpServletResponse response)throws Exception {
    BaseResponseInfo res = new BaseResponseInfo(); try {
        request.getSession().removeAttribute("user");
        request.getSession().removeAttribute("tenantId");
        request.getSession().removeAttribute("userNumLimit");
        request.getSession().removeAttribute("billsNumLimit");
        response.sendRedirect("/login.html");
    } catch(Exception e){
        e.printStackTrace();
        res.code = 500;
        res.data = "退出失败";
    } return res;
}

@PostMapping(value = "/resetPwd") public String resetPwd(@RequestParam("id") Long id,
                                 HttpServletRequest request) throws Exception {
    Map objectMap = new HashMap();
    String password = "123456";
    String md5Pwd = Tools.md5Encryp(password); int update = userService.resetPwd(md5Pwd, id); if(update > 0) { return returnJson(objectMap, message, ErpInfo.OK.code);
    } else { return returnJson(objectMap, message, ErpInfo.ERROR.code);
    }
}

@PostMapping(value = "/updatePwd") public String updatePwd(@RequestParam("userId") Long userId, @RequestParam("password") String password,
                        @RequestParam("oldpwd") String oldpwd, HttpServletRequest request)throws Exception {
    Integer flag = 0;
    Map objectMap = new HashMap(); try {
        User user = userService.getUser(userId);
        String oldPassword = Tools.md5Encryp(oldpwd);
        String md5Pwd = Tools.md5Encryp(password); //必须和原始密码一致才可以更新密码  if(user.getLoginame().equals("jsh")){
            flag = 3; //管理员jsh不能修改密码  } else if (oldPassword.equalsIgnoreCase(user.getPassword())) {
            user.setPassword(md5Pwd);
            flag = userService.updateUserByObj(user); //1-成功  } else {
            flag = 2; //原始密码输入错误  }
        objectMap.put("status", flag); if(flag > 0) { return returnJson(objectMap, message, ErpInfo.OK.code);
        } else { return returnJson(objectMap, message, ErpInfo.ERROR.code);
        }
    } catch (Exception e) {
        logger.error(">>>>>>>>>>>>>修改用户ID为 : "  userId "密码信息失败", e);
        flag = 3;
        objectMap.put("status", flag); return returnJson(objectMap, message, ErpInfo.ERROR.code);
    }
} /**  * 获取全部用户数据列表  * @param request  * @return  */  @GetMapping(value = "/getAllList") public BaseResponseInfo getAllList(HttpServletRequest request)throws Exception {
    BaseResponseInfo res = new BaseResponseInfo(); try {
        Map data = new HashMap();
        List dataList = userService.getUser(); if(dataList!=null) {
            data.put("userList", dataList);
        }
        res.code = 200;
        res.data = data;
    } catch(Exception e){
        e.printStackTrace();
        res.code = 500;
        res.data = "获取失败";
    } return res;
} /**  * create by: cjl  * description:  * 查询分页用户列表  * create time: 2019/3/8 15:08  * @Param: pageSize   * @Param: currentPage   * @Param: search  * @return java.lang.String  */  @GetMapping(value = "/getUserList") public String getUserList(@RequestParam(value = Constants.PAGE_SIZE, required = false) Integer pageSize,
                                   @RequestParam(value = Constants.CURRENT_PAGE, required = false) Integer currentPage,
                                   @RequestParam(value = Constants.SEARCH, required = false) String search)throws Exception {

    Map parameterMap = new HashMap(); //查询参数  JSONObject obj= JSON.parseObject(search);
    Set key= obj.keySet(); for(String keyEach: key){
        parameterMap.put(keyEach,obj.getString(keyEach));
    }
    PageQueryInfo queryInfo = new PageQueryInfo();
    Map objectMap = new HashMap(); if (pageSize == null || pageSize <= 0) {
        pageSize = BusinessConstants.DEFAULT_PAGINATION_PAGE_SIZE;
    } if (currentPage == null || currentPage <= 0) {
        currentPage = BusinessConstants.DEFAULT_PAGINATION_PAGE_NUMBER;
    }
    PageHelper.startPage(currentPage,pageSize,true);
    List list = userService.getUserList(parameterMap); //获取分页查询后的数据  PageInfo pageInfo = new PageInfo<>(list);
    objectMap.put("page", queryInfo); if (list == null) {
        queryInfo.setRows(new ArrayList());
        queryInfo.setTotal(BusinessConstants.DEFAULT_LIST_NULL_NUMBER); return returnJson(objectMap, "查找不到数据", ErpInfo.OK.code);
    }
    queryInfo.setRows(list);
    queryInfo.setTotal(pageInfo.getTotal()); return returnJson(objectMap, ErpInfo.OK.name, ErpInfo.OK.code);
} /**  * create by: cjl  * description:  * 新增用户及机构和用户关系  * create time: 2019/3/8 16:06  * @Param: beanJson  * @return java.lang.Object  */  @PostMapping("/addUser")
@ResponseBody public Object addUser(@RequestParam("info") String beanJson, HttpServletRequest request)throws Exception{
    JSONObject result = ExceptionConstants.standardSuccess();
    Long userNumLimit = Long.parseLong(request.getSession().getAttribute("userNumLimit").toString());
    Long count = userService.countUser(null,null); if(count>= userNumLimit) { throw new BusinessParamCheckingException(ExceptionConstants.USER_OVER_LIMIT_FAILED_CODE,
                ExceptionConstants.USER_OVER_LIMIT_FAILED_MSG);
    } else {
        UserEx ue= JSON.parseObject(beanJson, UserEx.class);
        userService.addUserAndOrgUserRel(ue);
    } return result;
} /**  * 注册用户  * @param loginame  * @param password  * @return  * @throws Exception  */  @PostMapping(value = "/registerUser") public Object registerUser(@RequestParam(value = "loginame", required = false) String loginame,
                           @RequestParam(value = "password", required = false) String password,
                           HttpServletRequest request)throws Exception{
    JSONObject result = ExceptionConstants.standardSuccess();
    UserEx ue= new UserEx();
    ue.setUsername(loginame);
    ue.setLoginame(loginame);
    ue.setPassword(password);
    userService.checkUserNameAndLoginName(ue); //检查用户名和登录名  ue = userService.registerUser(ue,manageRoleId,request); return result;
} /**  * create by: cjl  * description:  * 修改用户及机构和用户关系  * create time: 2019/3/8 16:06  * @Param: beanJson  * @return java.lang.Object  */  @PostMapping("/updateUser")
@ResponseBody public Object updateUser(@RequestParam("info") String beanJson,@RequestParam("id") Long id)throws Exception{
    JSONObject result = ExceptionConstants.standardSuccess();
    UserEx ue= JSON.parseObject(beanJson, UserEx.class);
    ue.setId(id);
    userService.updateUserAndOrgUserRel(ue); return result;
}
@PostMapping("/deleteUser")
@ResponseBody public Object deleteUser(@RequestParam("ids") String ids)throws Exception{
    JSONObject result = ExceptionConstants.standardSuccess();
    userService.batDeleteUser(ids); return result;
}
@PostMapping("/batchDeleteUser")
@ResponseBody public Object batchDeleteUser(@RequestParam("ids") String ids)throws Exception{
    JSONObject result = ExceptionConstants.standardSuccess();
    userService.batDeleteUser(ids); return result;
}
@RequestMapping("/getOrganizationUserTree") public JSONArray getOrganizationUserTree()throws Exception{
    JSONArray arr=new JSONArray();
    List organizationUserTree= userService.getOrganizationUserTree(); if(organizationUserTree!=null&&organizationUserTree.size()>0){ for(TreeNodeEx node:organizationUserTree){
            String str=JSON.toJSONString(node);
            JSONObject obj=JSON.parseObject(str);
            arr.add(obj) ;
        }
    } return arr;
}
  • 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
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195

}

以下内容无关:

-------------------------------------------分割线---------------------------------------------

环境信息:
mysql:5.7.32

seata-server:1.4.1

SpringCloud:Hoxton.SR10

SpringBoot:2.3.8.RELEASE

注册中心:Eureka

涉及服务:

Seata-server
1、在file.conf中修改

mode = “db”

然后配置DB信息:

database store property

db {undefined
datasource = “druid”
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = “mysql”
driverClassName = “com.mysql.jdbc.Driver”
url = “jdbc:mysql://127.0.0.1:3306/seata”
user = “root”
password = “123456”
minConn = 5
maxConn = 100
globalTable = “global_table”
branchTable = “branch_table”
lockTable = “lock_table”
queryLimit = 100
maxWait = 5000
}
2、在register.conf

registry {undefined

file 、nacos 、eureka、redis、zk、consul、etcd3、sofa

type = “eureka”
loadBalance = “RandomLoadBalance”
loadBalanceVirtualNodes = 10
eureka {undefined
serviceUrl = “http://eureka-chengdu:8761/eureka,http://eureka-hangzhou:8762/eureka”
application = “seata-server”
weight = “1”
}
3、客户端修改

这里所指的客户端包含所有的资源管理器,包含所有需要seata-server管理的服务

在服务启动yml中增加:

seata:
enabled: true

事务群组(可以每个应用独立取名,也可以使用相同的名字)

tx-service-group: my_tx_group
client:
rm-report-success-enable: true
# 异步提交缓存队列长度(默认10000)
rm-async-commit-buffer-limit: 1000
# 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)
tm-commit-retry-count: 3
# 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)
tm-rollback-retry-count: 3
support:
# 数据源自动代理开关(默认false关闭)
spring-datasource-autoproxy: false
service:
vgroup-mapping:
# TC 集群(必须与seata-server保持一致)
my_tx_group: seata-server
grouplist:
default: seata-server:8091
registry:
type: eureka
eureka:
serviceUrl: http://eureka-chengdu:8761/eureka/,http://eureka-hangzhou:8762/eureka/
TCC模式
TCC模式实践需要四个服务,除了seata-server外,其他服务调用关系如下:

business服务是全局事务的发起者,需要增加@GlobalTransactional注解

@Override
@GlobalTransactional
public String processTcc(Map params) {undefined
String xid = RootContext.getXID();
System.out.println(("—》》》》xid:" + xid));
uploadFeign.upload(params);
downloadFeign.download(params);
return xid;
}
business服务会通过feign远程调用upload和download服务,这两个服务都要声明TCC的三个接口,并通过TwoPhaseBusinessAction注解声明。

upload服务:
@LocalTCC
public interface TccService {undefined
@TwoPhaseBusinessAction(name = “upload”, commitMethod = “commitTcc”, rollbackMethod = “cancel”)
String upload(@BusinessActionContextParameter(paramName = “params”) Map params);

boolean commitTcc(BusinessActionContext context);

boolean cancel(BusinessActionContext context);
  • 1
  • 2
  • 3

}
具体实现,这里模拟了TCC结果并放到Result中,通过restful接口可以查看,实际业务需要考虑防悬挂和空回滚问题,例子只是简单描述如何使用TCC模式:

@Slf4j
@Service
public class TccServiceImpl implements TccService {undefined
@Value("${spring.application.name}")
private String appName;

@PostConstruct
private void initAppName() {
    Result.getResult().setAppName(appName);
}

@Override
public String upload(Map params) {
    String xid = RootContext.getXID();
    System.out.println(("---》》》》xid: " + xid));
    return "success";
}

@Override
public boolean commitTcc(BusinessActionContext context) {
    String xbid = context.getXid();
    System.out.println(("---》》》》xid: " + xbid + "提交成功"));
    Result.getResult().setActionResult(context.getXid(), +context.getBranchId(), "Commit", context.getActionContext("params"));
    return true;
}

@Override
public boolean cancel(BusinessActionContext context) {
    System.out.println(("---》》》》xid: " + context.getXid() + "回滚成功"));
    Result.getResult().setActionResult(context.getXid(), context.getBranchId(), "Rollback", context.getActionContext("params"));
    return true;
}
  • 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

}

download服务
download服务也同样需要声明一个TCC接口,实现上在Try阶段模拟每三次调用,,延迟30s失败一次场景

@Override
public String download(Map params) {undefined
String xid = RootContext.getXID();
System.out.println(("—》》》》xid: " + xid));
if (count.incrementAndGet() % 3 == 0) {undefined
try {undefined
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {undefined
log.warn(“InterruptedException”, e);
}
throw new RuntimeException(“服务异常”);
}
return “success”;
}
测试
1、通过restful接口调用两次,返回全局事务ID

2、查看download和upload服务结果,可以看到结果都是成功。

原文:https://blog.csdn.net/weixin_43322764/article/details/115465704

联系站长

QQ:769220720

Copyright © SibooSoft All right reserved 津ICP备19011444号