B075-项目实战--寻主消息发布 查看 处理 地图

目录

      • 业务介绍
        • 业务概述
        • 表设计
        • 宠物模块搭建
      • 发布寻主消息
        • 前台
        • 后端
          • 百度地图技术
            • 概述:
            • 应用:
          • 拷贝DistanceUtil和point
          • SearchMasterMsgController
          • SearchMasterMsgServiceImpl
      • 消息查看
        • 思路
        • 后端
          • SearchMasterMsgController
          • SearchMasterMsgServiceImpl
          • SearchMasterMsgMapper
        • 后台
          • 页面准备
      • 消息处理
        • 后台
        • 后端
          • SearchMasterMsgController
          • SearchMasterMsgServiceImpl
          • SearchMasterMsgMapper
        • 后台完成

业务介绍

业务概述

用户发布寻主消息到平台,平台收到消息后匹配最近门店去上门收购,然后可以上架发布售卖,
发布消息,展示消息,处理消息
发布,收购,上架,领养

百度地图技术:地址关键字自动匹配补全,

需求分析与流程设计中一般不同的名词对应着不同的表,要了解表的字段和能完成的功能

1 用户发布寻主消息
2 平台接收消息
3 找到最近门店,发送短信消息给门店管理员,并且把这个寻主消息划归他门下
4 收取宠物,如果要钱的,还要创建订单并完成支付

名词
寻主消息,宠物类型,宠物,宠物详情,寻主订单(服务订单,商品订单,充值订单等)

表设计

寻主消息表

CREATE TABLE `t_search_master_msg` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL COMMENT '宠物名称',
  `age` int(10) DEFAULT NULL,
  `gender` tinyint(1) DEFAULT NULL,
  `coat_color` varchar(255) DEFAULT NULL COMMENT '毛色',
  `resources` varchar(255) DEFAULT NULL,
  `pet_type` bigint(255) DEFAULT NULL COMMENT '类型',
  `price` double(10,3) DEFAULT NULL,
  `address` varchar(255) DEFAULT '',
  `state` int(11) DEFAULT '0' COMMENT '待处理 0 已处理1',
  `title` varchar(255) DEFAULT NULL,
  `user_id` bigint(255) DEFAULT NULL,
  `shop_id` bigint(20) DEFAULT NULL COMMENT '店铺id 消息分配的店铺',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=315 DEFAULT CHARSET=utf8;

宠物类型表

CREATE TABLE `t_pet_type` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `description` text,
  `pid` bigint(20) DEFAULT NULL COMMENT '父类型id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

宠物表,search_master_msg_id要允许为null

CREATE TABLE `t_pet` (
  `id` bigint(2) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `saleprice` decimal(19,2) DEFAULT NULL,
  `costprice` varchar(255) DEFAULT NULL,
  `resources` varchar(255) DEFAULT NULL,
  `state` bigint(2) DEFAULT NULL COMMENT '状态:0下架 1上架',
  `type_id` bigint(20) DEFAULT NULL COMMENT '类型id',
  `offsaletime` datetime DEFAULT NULL,
  `onsaletime` datetime DEFAULT NULL,
  `createtime` datetime DEFAULT NULL,
  `shop_id` bigint(20) DEFAULT NULL COMMENT '店铺Id 如果被领养店铺id为null',
  `user_id` bigint(20) DEFAULT NULL COMMENT '如果被领养为领养用户id',
  `search_master_msg_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;

宠物详情表

CREATE TABLE `t_pet_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `pet_id` bigint(20) DEFAULT NULL,
  `adoptNotice` text COMMENT '领养须知',
  `intro` text COMMENT '简介',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;

宠物模块搭建

java,xml,yml

发布寻主消息

前台

拷贝publish页面到ph-web根目录,从我的福利开新窗体跳转

<div class="nav-extra" @click="goPublish">
	<i class="am-icon-user-secret am-icon-md nav-user" @>i><b>b>发布寻主消息
	<i class="am-icon-angle-right" style="padding-left: 10px;">i>
div>
        methods:{
            goPublish(){//跳转到发布寻主消息页面
                window.open("publish.html");
            }
        },

publish.html修改引入路径,删除最后一个无关的div

后端

百度地图技术
概述:

百度地图开发平台:http://lbsyun.baidu.com/
控制台 - 应用管理 - 我的应用 - 创建应用 应用名称:pethome 应用类型:浏览器端 Referer白名单:*(即所有域名皆可访问)

逆地址解析示例:开发文档 - JavaScript API - 示例DEMO - 路线规划 - 步行规划 - 根据起终点名称规划步行线路

检索服务 - 输入提示示例 - 关键字提示输入 - 输入地址可匹配相关地址

应用:

拷贝百度关键字提示输入代码到ph-web根目录mapTest.html,换上自己的秘钥
1.publish引入百度地图,


<script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=h7cuNiHW3f2Sz1OsCEbzCDfkUEmwLHNA">script>

2.拷贝整个百度地图js到publish,(取消初始定位)

见工程

0.绑定表单id(已对齐),


<div class="am-form-group">
	<label for="suggestId" class="am-form-label">地址label>
	<div class="am-form-content">
		<input type="text" id="suggestId" v-model="searchMasterMsg.address" placeholder="请输入地址">
	div>
div>
    var ac = new BMap.Autocomplete(    //建立一个自动完成的对象
        {"input" : "suggestId"
            ,"location" : map
        });

4.将返回的结果集赋值给address,

    var myValue;
    ac.addEventListener("onconfirm", function(e) {    //鼠标点击下拉列表后的事件
        var _value = e.item.value;
        myValue = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
        G("searchResultPanel").innerHTML ="onconfirm
index = "
+ e.item.index + "
myValue = "
+ myValue; vue.searchMasterMsg.address = myValue; setPlace(); });
拷贝DistanceUtil和point

Point

/**
 * 存放经纬度
 */
@Data
public class Point {
    //经度
    private Double lng;
    //维度
    private Double lat;
}

DistanceUtil

package cn.ming;

import cn.ming.org.domain.Shop;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

/**
 * 位置相关工具类
 */
public class DistanceUtil {
    public static  Point getPoint(String address){
        String Application_ID="h7cuNiHW3f2Sz1OsCEbzCDfkUEmwLHNA";//配置上自己的百度地图应用的AK
        try{
            String sCurrentLine; String sTotalString;sCurrentLine ="";
            sTotalString = "";
            InputStream l_urlStream;
//          URL l_url = new java.net.URL("http://api.map.baidu.com/geocoder/v2/?address="+address.replaceAll(" ","")+"&output=json&ak="+Application_ID+"&callback=showLocation");
            URL l_url = new URL("http://api.map.baidu.com/geocoding/v3/?address="+address+"&output=json&ak="+Application_ID+"&callback=showLocation");
            HttpURLConnection l_connection = (HttpURLConnection) l_url.openConnection();
            l_connection.connect();
            l_urlStream = l_connection.getInputStream();
            java.io.BufferedReader l_reader = new java.io.BufferedReader(new InputStreamReader(l_urlStream));
            String str=l_reader.readLine();
            System.out.println(str);
            //用经度分割返回的网页代码  
            String s=","+"\""+"lat"+"\""+":";
            String strs[]=str.split(s,2);
            String s1="\""+"lng"+"\""+":";
            String a[]=strs[0].split(s1, 2);
            s1="}"+","+"\"";
            String a1[]=strs[1].split(s1,2);

            Point point=new Point();
            point.setLng(Double.valueOf(a[1]));
            point.setLat(Double.valueOf(a1[0]));
            return point;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //地球半径,进行经纬度运算需要用到的数据之一
    private static final double EARTH_RADIUS = 6378137;
    //根据坐标点获取弧度
    private static double rad(double d)
    {
        return d * Math.PI / 180.0;
    }

    /**
     * 根据两点间经纬度坐标(double值),计算两点间距离,单位为米
     * @param point1 A点坐标
     * @param point2 B点坐标
     * @return
     */
    public static double getDistance(Point point1,Point point2)
    {
        double radLat1 = rad(point1.getLat());
        double radLat2 = rad(point2.getLat());
        double a = radLat1 - radLat2;
        double b = rad(point1.getLng()) - rad(point2.getLng());
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
                Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }

    /**
     * 根据两点间经纬度坐标(double值),计算两点间距离,单位为米
     * @param point 用户指定的地址坐标
     * @param shops 商店
     * @return
     */
    public static Shop getNearestShop (Point point, List<Shop> shops) {

        //如果传过来的集合只有一家店铺,那么直接将这家店铺的信息返回就是最近的店铺了
        Shop shop=shops.get(0);
        //获取集合中第一家店铺到指定地点的距离
        double distance=getDistance(point,getPoint(shops.get(0).getAddress()));
        //如果有多家店铺,那么就和第一家店铺到指定地点的距离做比较
        if (shops.size()>1){
            for (int i=1;i<shops.size();i++){
                if (getDistance(point,getPoint(shops.get(i).getAddress()))<distance){
                    shop=shops.get(i);
                }
            }
        }
        return shop;
    }

    public static void main(String[] args) {
        System.out.println(getPoint("成都市武侯区天府新谷-10号楼"));
    }
}
SearchMasterMsgController
    /**
     * 发布寻主消息
     */
    @PostMapping("/publish")
    public AjaxResult publish(@RequestBody SearchMasterMsg searchMasterMsg, HttpServletRequest request){
        try {
            Logininfo loginInfo = LoginContext.getLoginIn(request);
            seachMasterMsgService.publish(searchMasterMsg, loginInfo.getId());
            return AjaxResult.me();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.me().setMessage("发布失败!"+e.getMessage());
        }
    }
SearchMasterMsgServiceImpl
    @Override
    @Transactional
    public void publish(SearchMasterMsg searchMasterMsg, Long loginInfoId) {
        //1.找到最近的门店  绑定门店到寻主消息
        // 1.1用地址计算发布寻主消息人员的经纬度
        Point point = DistanceUtil.getPoint(searchMasterMsg.getAddress());
        //1.2 根据点计算出最近的门店
        Shop nearestShop = DistanceUtil.getNearestShop(point, shopMapper.loadAll());
        searchMasterMsg.setShop(nearestShop);
        searchMasterMsg.setShop_id(nearestShop.getId());
        //2.绑定谁发的消息(user)
        User user = userMapper.loadByloginInfoId(loginInfoId);
        searchMasterMsg.setUser(user);
        searchMasterMsg.setUser_id(user.getId());
        //3.存储寻主消息
        searchMasterMsgMapper.save(searchMasterMsg);
        // 4.  发送消息通知店铺管理员
        //SmsUtils.sendSms(nearestShop.getTel(), "老板,你有【"+searchMasterMsg.getName()+"】,快去接客!");
        System.out.println("老板,你有【"+searchMasterMsg.getName()+"】消息,快去接客!");
    }

消息查看

思路

简单做:用户可查,平台管理员可查,店铺人员可查(店铺管理员 店铺员工都可以),分作3个接口

待处理消息和已处理消息两个页面

待处理消息:平台管理员可看全部,被分配的店铺人员可看自己的

后台查看:
employee的shopid属于某店铺,则这些employee都可查自己店铺的所有消息 - 给后台用
message里没有user也没有shop,没有分配的平台管理员都可以看 - 给后台用
用户只能查看自己订单 user_id - 给前台用

平台+用户+已处理

待处理消息接口(平台人员看全部+店铺人员看自己),
已处理消息接口(平台人员看全部+店铺人员看自己),
用户看自己消息的接口(自己的待处理消息+已处理消息)

后端

SearchMasterMsgController
    /**
     * 待处理消息查询接口,平台管理员 + 店铺员工(店铺管理员 + 员工)
     * 待处理消息查询接口,平台管理员和店铺人员都可以进来查,根据是否存在shopid分别查到各自可以看的数据
     */
    @PostMapping("/pending")
    public PageList<SearchMasterMsg> pending(@RequestBody SearchMasterMsgQuery query, HttpServletRequest request){
        try {
            Logininfo loginInfo = LoginContext.getLoginIn(request);
            return seachMasterMsgService.pending(query, loginInfo.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 已处理消息查询接口,平台管理 + 店铺员工(店铺管理员 + 员工)
     * 已处理消息查询接口,同上,只是类型参数不一样
     */
    @PostMapping("/processed")
    public PageList<SearchMasterMsg> processed(@RequestBody SearchMasterMsgQuery query, HttpServletRequest request){
        try {
            Logininfo loginInfo = LoginContext.getLoginIn(request);
            return seachMasterMsgService.processed(query, loginInfo.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 前端用户查询自己消息的接口
     * 前端用户查询自己消息的接口,已处理待处理都能查
     */
    @PostMapping("/user")
    public PageList<SearchMasterMsg> queryUser(@RequestBody SearchMasterMsgQuery query, HttpServletRequest request){
        try {
            Logininfo loginInfo = LoginContext.getLoginIn(request);
            return seachMasterMsgService.queryUser(query, loginInfo.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
SearchMasterMsgServiceImpl
    //待处理消息查询接口,平台管理员和店铺人员都可以进来查,根据是否存在shopid分别查到各自可以看的数据
    @Override
    public PageList<SearchMasterMsg> pending(SearchMasterMsgQuery query, Long loginInfoId) {
        query.setState(0);              //SearchMasterMsgQuery  state  0待处理  1已处理
        //1.通过loginInfoID查询出Employee
        Employee employee = employeeMapper.loadByLoginInfoId(loginInfoId);
        //2.如果employee中的shopID不为null,就是店铺工作人员。否则就是平台员工
        if(employee.getShop_id() != null){
            query.setShopId(employee.getShop_id());//把员工的shopid放到分页查询条件里 SearchMasterMsgQuery shopId
        }
        return super.queryPage(query);  //SearchMasterMsgQuery 返回查询结果
    }

    //已处理消息查询接口,同上,只是类型参数不一样
    @Override
    public PageList<SearchMasterMsg> processed(SearchMasterMsgQuery query, Long loginInfoId) {
        query.setState(1);
        //1.通过loginInfoID查询出Employee
        Employee employee = employeeMapper.loadByLoginInfoId(loginInfoId);
        //2.如果employee中的shopID不为null,就是店铺。否则就是平台员工
        if(employee.getShop_id() != null){
            query.setShopId(employee.getShop_id());     //因为shopId如果有值,就是查询门店的数据
        }
        return super.queryPage(query);
    }

    //前端用户查询自己消息的接口,已处理待处理都能查
    @Override
    public PageList<SearchMasterMsg> queryUser(SearchMasterMsgQuery query, Long loginInfoId) {
        User user = userMapper.loadByloingInfoId(loginInfoId);
        query.setUserId(user.getId());      //因为UserId如果有值,查询用户
        return super.queryPage(query);
    }
SearchMasterMsgMapper
    <sql id="whereSql">
        <where>
            <if test="state!=null">
               and a.state = #{state}
            if>
            <if test="userId!=null">
               and a.user_id = #{userId}
            if>
            <if test="shopId!=null">
              and  a.shop_id = #{shopId}
            if>
        where>
    sql>
    
    
    <select id="queryCount" parameterType="SearchMasterMsgQuery" resultType="integer">
        select count(*) from t_search_master_msg a
        <include refid="whereSql"/>
    select>
    
    
    <select id="queryData" parameterType="SearchMasterMsgQuery" resultMap="SearchMasterMsgMap">
        SELECT
            a.*, u.id uid,
            u.username,
            s.id sid,
            s. NAME sname,
            t.id tid,
            t.name tname
        FROM
            t_search_master_msg a
        LEFT JOIN t_user u ON u.id = a.user_id
        LEFT JOIN t_shop s ON s.id = a.shop_id
        LEFT JOIN t_pet_type t on t.id = a.pet_type
        <include refid="whereSql"/>
        limit #{start},#{pageSize}
    select>

后台

页面准备

拷贝SearchMasterMsgPending.vue和SearchMasterMsgProcessed.vue到ph-admin的pet包下

配置路由

构造数据后即可测试

消息处理

点击处理

后台

后端

SearchMasterMsgController
    /**
     * 处理消息
     */
    @PutMapping("/handle")
    public AjaxResult handle(@RequestBody Pet pet){
        try {
            seachMasterMsgService.handle(pet);
            return AjaxResult.me();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.me().setMessage("处理失败!"+e.getMessage());
        }
    }
SearchMasterMsgServiceImpl
    /**
     * 处理消息
     */
    @Override
    public void handle(Pet pet) {
        //1.改状态  --已处理
        searchMasterMsgMapper.updateStateForProcessed(pet.getSearch_master_msg_id());
        //2.生成宠物基本信息
        petMapper.save(pet);
        //3.宠物详情
        PetDetail detail = pet.getDetail();
        if(detail != null){
            detail.setPet_id(pet.getId());
            petDetailMapper.save(detail);
        }
        //4.生成订单@TODO
        //5.生成支付@TODO
    }
SearchMasterMsgMapper
    
    <update id="updateStateForProcessed" parameterType="long">
        UPDATE t_search_master_msg set state = 1 WHERE id = #{search_master_msg_id}
    update>

后台完成

你可能感兴趣的:(笔记总结,java,es6,前端,redis)