首页 > 分享 > 宠物O2O平台技术架构

宠物O2O平台技术架构

宠物之家

前言

本项目是一个o2o项目,以宠物为核心,提供宠物领养,宠物收购,宠物寻主,产品购买,服务购买等相关业务。前端用的vue技术栈,后端用的spring,springMVC,springboot,mybatis。

负责模块

用户模块
宠物模块
支付模块
##主要运用技术
1.redis
2.发送短信技术
3.微信三方登录技术
4.md5加密技术
5.RSA加密技术
6.支付宝三方支付技术
7.百度地图定位技术
8.quartz定时器
9.docker
##用户模块
需求:用户注册,用户登录,用户店铺收藏,用户浏览足迹

注册

在这里插入图片描述##表的设计注册方面我们设计了两张表,一张user用户信息表,和loginInfo登录信息表,把用户注册成功后的信息先存放在loginInfo表再存放在user表
在这里插入图片描述

后端代码实现

public AjaxResult getVerifyCode(Map<String, String> params) { String phone = params.get("phone"); //获取前台传来的手机号判断是否为空 if (!StringUtils.hasLength(phone)){ return AjaxResult.ajax().setSuccess(false).setMessage("请输入正确手机号!"); } //判断手机号是否已经存在 User user = mapper.findOneUser(phone); if(user!=null){ return AjaxResult.ajax().setSuccess(false).setMessage("该手机号已经被注册"); } //不存在,就判断redis里面是否有未过期的验证码,从redis获取短信验证码 String key="register"+phone; String value=(String) redisTemplate.opsForValue().get(key);//code:time //判断value是否为空 String code=""; //为空 if(!StringUtils.hasLength(value)){ code = StrUtils.getComplexRandomString(4); }else { //不为空就判断是否过了重复发短信的时间 long times = Long.valueOf(value.split(":")[1]); long millis = System.currentTimeMillis(); if(millis-times<1000*60*1){ return AjaxResult.ajax().setSuccess(false).setMessage("请不要重复发送短信"); }else { code=value.split(":")[0]; } } //把value放入redis redisTemplate.opsForValue().set(key,code+":"+System.currentTimeMillis(),3, TimeUnit.MINUTES); //发送短信 // Smsutil.sendSms(phone,code); System.out.println("发送的验证码为:"+code); return AjaxResult.ajax(); }

123456789101112131415161718192021222324252627282930313233343536

登录

设计流程图
在这里插入图片描述##表的设计
在登录方面我们设计了三张表,user用户信息表,employee员工信息表,loginInfo登录信息表,我们把user表和employ表中所有信息都放在了loginInfo表中,并用type字段来进行区分,在前后台登录实现的时候只需要调用一个接口查询一张表
在这里插入图片描述

后端实现代码

账号密码登录

public AjaxResult loginInfo(LoginDto loginDto) { //判断用户信息是否完善 String password1 = loginDto.getPassword(); if (StringUtils.isEmpty(loginDto.getUsername()) || StringUtils.isEmpty(password1) || StringUtils.isEmpty(loginDto.getType())) { return AjaxResult.ajax().setSuccess(false).setMessage("请输入完整信息"); } //判断账号是否存在 LoginInfo loginInfo1 = mapper.loadByUsername(loginDto); if (loginInfo1 == null) { return AjaxResult.ajax().setSuccess(false).setMessage("账号或密码错误1"); } //判断该账号是否可用 Integer disable = loginInfo1.getDisable(); if (disable == 0) { return AjaxResult.ajax().setMessage("该账号不可用").setSuccess(false); } //判断密码是否正确 String password = loginInfo1.getPassword(); String salt = loginInfo1.getSalt(); String md5 = MD5Utils.encrypByMd5(password1 + salt); if (!md5.equals(password)) { return AjaxResult.ajax().setSuccess(false).setMessage("账号或密码错误2"); //密码正确 } else { //生成tocken String tocken = UUID.randomUUID().toString(); template.opsForValue().set(tocken, loginInfo1, 30, TimeUnit.MINUTES); Map<Object, Object> map = new HashMap<>(); map.put("tocken", tocken); loginInfo1.setPassword(""); map.put("user", loginInfo1); String checked = loginDto.getChecked(); map.put("checked", checked); String pass = loginDto.getPassword(); map.put("pass", pass); String name = loginDto.getUsername(); map.put("name", name); return AjaxResult.ajax().setResultObj(map); } }

1234567891011121314151617181920212223242526272829303132333435363738394041424344

##微信登录
流程图设计
在这里插入图片描述##表的设计
三方登录我们还设计了一张微信用户信息表,用来保存相关的微信用户的信息
在这里插入图片描述

实现思路:
前台使用微信提供的接口,需要在其中配置回调页面–
当用户扫码后携带code授权码跳转到回调页面,封装绑定地址,授权码数据发送请求到后台–
后台通过code授权码,发送json请求获取到用户唯一标示(openid)和令牌(accessToken)–
通过openid获取用户信息,有就把用户信息放入redis返回前台,没有就返回绑定页面地址并携带
appenid和accesstoken–
用户在填完绑定信息发请求到后台–
判断用户信息是否填写完善–
通过手机号查询用户,有就通过openid拿到微信用户个人信息存入数据库–
没有,就先注册添加用户信息到loginfo表,user表再拿到微信个人信息存入数据库–
把用户信息放入redis,并返回前台,前台跳转首页

代码实现

//微信登录 public AjaxResult loginWeixin(Map<String, String> params) { String code = params.get("code"); String binderUrl = params.get("binderUrl"); //通过授权码来获取openid和access_token令牌 String url = WxConstants.GET_ACCESSTOKEN_URL. replace("APPID", WxConstants.APPID) .replace("SECRET", WxConstants.SECURITY) .replace("CODE", code); String JsonStr = HttpClientUtils.httpGet(url); JSONObject jsonObject = JSONObject.parseObject(JsonStr); //拿到openid和令牌access_token String accesstoken = jsonObject.getString("access_token"); String openid = jsonObject.getString("openid"); //通过openid拿到user用户 User user = userMapper.getByOpenid(openid); //判断如果拿到了就说明已经绑定,没拿到就跳转到绑定界面 if (user != null) { //拿到loginInfo LoginInfo loginInfo = mapper.loadById(user.getLogininfo_id()); //放入redis String tocken = UUID.randomUUID().toString(); template.opsForValue().set(tocken, loginInfo, 30, TimeUnit.MINUTES); HashMap<Object, Object> map = new HashMap<>(); map.put("tocken", tocken); loginInfo.setPassword(""); map.put("user", loginInfo); return AjaxResult.ajax().setResultObj(map); } else { binderUrl = binderUrl + "?accessToken=" + accesstoken + "&openid=" + openid; return AjaxResult.ajax().setResultObj(binderUrl).setMessage("binder").setSuccess(false); } } //微信绑定登录 public AjaxResult weixinBinder(LoginDto loginDto) { String accesstoken = loginDto.getAccesstoken(); String openid = loginDto.getOpenid(); System.out.println(accesstoken ); System.out.println(openid ); //通过accesstoken和openid拿到用户信息 String url = WxConstants.GET_USER_URL .replace("ACCESS_TOKEN", accesstoken) .replace("OPENID", openid); String JsonStr = HttpClientUtils.httpGet(url); //通过账号判断该用户是否存在,不存在就注册加绑定,存在就绑定 LoginInfo loginInfo = mapper.loadByUsername(loginDto); if (loginInfo == null) { loginInfo = loginDtotologinInfo(loginDto); mapper.insert(loginInfo); //拿到自增loginInfo的id User user = UserServiceImpl.LoginInfotoUser(loginInfo); //返回自增id userMapper.insert(user); //拿到user的id放入wxUser的 WxUser wxUser = usertoWxUser(user, JsonStr); wxUserMapper.save(wxUser); } else { //存在就判断密码直接绑定 String salt = loginInfo.getSalt(); String password = loginDto.getPassword(); String md5 = MD5Utils.encrypByMd5(password + salt); if (!md5.equals(loginInfo.getPassword())) { return AjaxResult.ajax().setSuccess(false).setMessage("账号或密码错误"); } String username = loginInfo.getUsername(); User user = userMapper.findOneUser(username); WxUser wxUser = usertoWxUser(user, JsonStr); wxUserMapper.save(wxUser); } //放入redis String tocken = UUID.randomUUID().toString(); template.opsForValue().set(tocken, loginInfo, 30, TimeUnit.MINUTES); HashMap<Object, Object> map = new HashMap<>(); map.put("tocken", tocken); loginInfo.setPassword(""); map.put("user", loginInfo); return AjaxResult.ajax().setResultObj(map); }

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182

其他收藏,足迹

宠物模块

##表的设计
宠物模块我们一共设计了四张表,宠物信息表,宠物表,宠物详情表,
宠物类型表
在这里插入图片描述

实现思路:
寻主:
用户发布寻主消息,存放寻主消息,把消息发送给最近的一家店铺,
店铺处理生成相关宠物信息以及收购订单。
领养:用户点击领养,后台生成订单,支付单。
后台代码:

@Override public void save(SeachMasterMsg msg, LoginInfo loginInfo) { //通过loginInfoid拿到user对象; User user = mapper.getById(loginInfo.getId()); //拿到userId放入SeachMasterMsg msg.setUser_id(user.getId()); //拿到用户地址经纬度 Point point = DistanceUtil.getPoint(msg.getAddress()); //拿到所有店铺地址 List<Shop> shops = shopMapper.findAll(); Shop nearestShop = DistanceUtil.getNearestShop(point, shops); if (nearestShop==null){ throw new RuntimeException("抱歉附近没有门店!") ; } //拿到最近的shop放入SeachMasterMsg,并给店铺管理员发信息 msg.setShop_id(nearestShop.getId()); Smsutil.sendSms(nearestShop.getAdmin().getPhone(),"老板附近有宠物可领取哦!" ); msgMapper.save(msg); } @Override//将信息转换成宠物 public void insert(Pet pet,LoginInfo loginIonf) { //将消息改为已处理 Long id = pet.getSeachmastermsg_id(); SeachMasterMsg seachMasterMsg = msgMapper.loadById(id); seachMasterMsg.setState(1); msgMapper.update(seachMasterMsg); //保存宠物信息(处理后的信息前台传来) petService.insert(pet); //生成订单 PetAcquisitionOrder petAcquisitionOrder = petto2order(pet,loginIonf,seachMasterMsg); petAcquisitionOrderMapper.save(petAcquisitionOrder); } @Override public void updateAdopt(Long id, LoginInfo loginInfo) { //拿到用户确认是谁领养的 User user = userMapper.getById(loginInfo.getId()); Pet pet = petMapper.loadById(id); pet.setUser_id(user.getId()); //修改为被领养状态 pet.setState(2); petMapper.update(pet); }

12345678910111213141516171819202122232425262728293031323334353637383940414243

其他 宠物详情的展示crud

支付模块(支付宝支付为例)

支付宝流程
在这里插入图片描述##表的设计
对于这个业务我们设计了三张表,支付表,支付流水表,支付宝支付信息表
在这里插入图片描述

实现思路:
后台封装了支付宝提供的接口–
当用户交订单就会生成支付订单,然后调用支付接口–
需要传入支付宝公钥,商家的私钥,统一支付单号,支付价格等信息–
支付宝返回一个支付数据包,把数据包返回前台–
前台解析数据包,拿到form表单,界面弹出支付二维码–
用户扫码之后同步回调到我们指定的页面,并异步回调后台指定的接口–
在接口修改相关订单及支付单的状态,并添加支付流水
设置定时器30分钟未支付就取消订单
实现代码

public AjaxResult productOrder(LoginInfo loginInfo, OrderDto dto) { Long id = dto.getAddress_id(); UserAddress userAddress = userAddressMapper.loadById(id); //添加主表ProductOrder ProductOrder productOrder = OrderDto2ProductOrder(loginInfo,dto,userAddress); String paySn = CodeGenerateUtils.generateUnionPaySn(); productOrder.setPaySn(paySn); productOrderMapper.save(productOrder); //添加到其他关联表,订单地址表 OrderAddress orderAddress=userAddressto2orderAddress(userAddress,productOrder); orderAddressMapper.save(orderAddress); //订单详情表 Long product_id = dto.getProduct_id(); Product product = productMapper.loadById(product_id); ProductOrderDetail productOrderDetail = productto2productDetail(product,productOrder); productOrderDetailMapper.save(productOrderDetail); //生成支付表单; PayBill payBill = productOrderto2payBill(productOrder,dto); payBill.setUnionPaySn(paySn); //保存单据 payBillMapper.save(payBill); //返回一个支付宝数据包会form表单返回给前台 String result = payBillService.pay(payBill); //设置订单超时取消 QuartzJobInfo info = new QuartzJobInfo(); info.setType(JobContstants.PRODUCT_ORDER_CANCEL); info.setJobName("product_order_cancel_"+productOrder.getId()); //会调用set方法转成conj形式 info.setFireDate(productOrder.getLastPayTime()); HashMap<String, Object> map = new HashMap<>(); map.put("orderId", productOrder.getId()); info.setParams(map); quartzService.addObj(info); return AjaxResult.ajax().setResultObj(result); } 支付宝工具类 public static String aliPay(AlipayInfo alipayInfo, PayBill payBill){ try { //获得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(Alipayconfig.gatewayUrl,alipayInfo.getAppid(), alipayInfo.getMerchant_private_key(), "json", Alipayconfig.charset, alipayInfo.getAlipay_public_key(), Alipayconfig.sign_type); //设置请求参数 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(Alipayconfig.return_url); alipayRequest.setNotifyUrl(Alipayconfig.notify_url); //商户订单号,商户网站订单系统中唯一订单号,必填 String out_trade_no = new String(payBill.getUnionPaySn()); //付款金额,必填 String total_amount = new String(payBill.getMoney().toString()); //订单名称,必填 String subject = new String(payBill.getDigest()); //商品描述,可空 String body = new String("服务订单"); alipayRequest.setBizContent("{"out_trade_no":""+ out_trade_no +""," + ""total_amount":""+ total_amount +""," + ""subject":""+ subject +""," + ""body":""+ body +""," + ""product_code":"FAST_INSTANT_TRADE_PAY"}"); //请求 String result = alipayClient.pageExecute(alipayRequest).getBody(); return result; //输出 } catch (Exception e) { e.printStackTrace(); } return null; } /* * *类名:AlipayConfig *功能:基础配置类 *详细:设置帐户有关信息及返回路径 *修改日期:2017-04-05 *说明: *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 */ //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ // 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 public static String notify_url = "http://syupi2.natappfree.cc/notify"; // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 public static String return_url = "http://localhost/success.html"; // 支付宝网关 public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; public static String sign_type = "RSA2"; public static String charset = "utf-8";

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192

微信,余额支付实现思路差不多

相关知识

宠物O2O平台技术架构
O2O宠物平台
平台导航+垂直平台=未来社区O2O平台
springboot+vue本地宠物o2o平台的设计与实现【开题+程序+论文】
八大宠物O2O平台引领宠物行业互联网+新风潮
盘点十大宠物O2O平台 相伴有你!
相伴有你!盘点十大宠物O2O平台
宠物领养平台:SpringBoot技术架构
美宠:上门宠物服务O2O平台,已获中路数百万投资
浅谈移动O2O宠物医疗平台的盈利模式

网址: 宠物O2O平台技术架构 https://m.mcbbbk.com/newsview1144406.html

所属分类:萌宠日常
上一篇: 买狗去哪个网站买可靠
下一篇: 猫咪购买推荐(哪个平台买猫最靠谱