项目系列-1

体检中心


/*
	体检中心小结:
	   前面就是检查项,检查组,套餐的CRUD,图片上传,后面是预约,spring security的权限认证,再就是报表相关和百度地图

*/

该项目在做的时候在数据库操作上有两种选择,一种是dao接口搭配xml映射文件,一种是纯注解方式,本人使用的是纯注解方式,所以以下代码关于dao部分都是注解代码,一般情况下,只需要在引号中写sql语句就可以了,但如果涉及到动态sql的话,简单方式是在引号中加,然后将原本的sql语句写到中间去就可以了,至于一些其它的标签比如SelectKey,具体操作看下面sql,不过一般是

@SelectKey(statement = “select last_insert_id()”, keyProperty = “id”, before = false, resultType = Integer.class)

第一天

重点

//环境搭建
/*
	功能架构---SOA Service Oriented Architecture

	
*/
//element-ui

第二天

/*
1.检查项增加功能
*/
@Insert("insert into t_checkitem(code,name,sex,age,price,type,remark,attention)\n" +
            "                      values\n" +
            "        (#{code},#{name},#{sex},#{age},#{price},#{type},#{remark},#{attention})")
    public void add(CheckItem checkItem);
/*
2.检查项分页查询
	分页查询的时候使用分页助手
	需要的注意的是条件查询的时候返回的结果不是对象集合,而是Page类的对象
	之后再从Page对象获取需要的值,代码如下:
*/
public PageResult pageQuery(QueryPageBean queryPageBean) {
        Integer currentPage = queryPageBean.getCurrentPage();
        Integer pageSize = queryPageBean.getPageSize();
        String queryString = queryPageBean.getQueryString();
        //调用分页助手
        PageHelper.startPage(currentPage,pageSize);
        //调用dao返回查询结果
        Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
        long total = page.getTotal();
        List<CheckItem> rows = page.getResult();

        return new PageResult(total,rows);
}

@Select("<script>select * from t_checkitem <if test=\"value !=null and value.length > 0 \">where code = #{value} or name = #{value} </if></script>")
    public Page<CheckItem> selectByCondition(String queryString);


/*
3.检查项编辑功能
	编辑功能涉及两方面:
	一方面:当点击编辑按钮时,显示编辑窗口,把需要的数据回显在窗口卡片上
		   需要发送3个请求:
		   		1.根据id查询检查组基本信息
		   		2.查询所有检查项信息
		   		3.根据检查组id查询该检查组包含的检查项,并且显示在检查项卡片上
	另一方面:点击编辑窗口的确定按钮触发handleEdit()方法,里面的ajax发送形式如下
	axios.post("/checkgroup/edit.do?checkitemIds="+this.checkitemIds,this.formData)
		 .then((res) => {})
		 .finally(() => {})
		注意看这里的checkitemIds参数直接跟在URL后面,表格参数放在逗号后面,在controller里面接收的时候
		要注意formdata里的数据要封入的对象需要用@RequestBody修饰,而checkitemIds直接用同名 		
        checkitemIds接收就可以了
*/

/*		
4.检查项删除功能
	删除检查项的时候得先判断该检查项是否与检查组有关联,如果有则不能删除
	代码如下:
*/
//删除之前先判断检查项是否跟检查组相关联
	long count = checkItemDao.findCountByCheckItemId(id);
    if (count > 0) {
    //有关联,不操作
    throw new RuntimeException();
    }
    //无关联
    checkItemDao.deleteById(id);

第三天

/*
	1.checkGroup检查组的增加
		增加检查组的时候,dao层可以用xml配置文件操作数据库,也可以用纯注解方式操作数据库
		纯注解方式如下:
*/
    @Insert("insert into t_checkgroup(code,name,sex,helpCode,remark,attention)\n" +
            "                      values\n" +
            "        (#{code},#{name},#{sex},#{helpCode},#{remark},#{attention})")
    @SelectKey(statement = "select last_insert_id()", keyProperty = "id", before = false, 				 resultType = Integer.class)
    public void add(CheckGroup checkGroup);
/*
	2.分页查询
		基本思想跟检查项分页一样,查的表不一样而已
*/

/*
	3.检查组编辑---包含单个检查组查询,单个检查组查询涉及多对多关系,具体sql看下面
		单个检查组查询是在前端页面回显数据时候用到
		因为更新检查组涉及到与检查项的关联,所以在更新新的关系之前可以先把旧的关系都删掉,再来存入新的关系
		最后更新的时候也涉及到动态语句
*/
@Update("<script>update t_checkgroup\n" +
            "        <set>\n" +
            "            <if test=\"name != null\">\n" +
            "                name = #{name},\n" +
            "            </if>\n" +
            "            <if test=\"sex != null\">\n" +
            "                sex = #{sex},\n" +
            "            </if>\n" +
            "            <if test=\"code != null\">\n" +
            "                code = #{code},\n" +
            "            </if>\n" +
            "            <if test=\"helpCode != null\">\n" +
            "                helpCode = #{helpCode},\n" +
            "            </if>\n" +
            "            <if test=\"attention != null\">\n" +
            "                attention = #{attention},\n" +
            "            </if>\n" +
            "            <if test=\"remark != null\">\n" +
            "                remark = #{remark},\n" +
            "            </if>\n" +
            "        </set>\n" +
            "        where id = #{id}</script>")
    public void edit(CheckGroup checkGroup);

@Select("select * from t_checkgroup where id in (select checkgroup_id from t_setmeal_checkgroup where setmeal_id = #{setmeal_id})")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "code",property = "code"),
            @Result(column = "helpCode",property = "helpCode"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "remark",property = "remark"),
            @Result(column = "attention",property = "attention"),
            @Result(
                    property = "checkItems",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = ("com.zz.dao.CheckItemDao.findCheckItemById"))
            )
    })
    public List<CheckGroup> findCheckGroupById(int id);

第四天

 //文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象
                handleAvatarSuccess(response, file) {
                    //上传成功后给imageUrl赋值
                    this.imageUrl = "http://q4754trxz.bkt.clouddn.com/" + response.data;
                    //弹出消息
                    this.$message({
                        type:response.flag ? 'success':'error',
                        message:response.message
                    });
                    this.formData.img = response.data;
                }
//这里注意发送请求不是我们平时用的ajax,所有返回的response跟我们之前返回的值不同,不用res.data.data获取数据,直接response.data或者response.flag获取数据

//另外,这里的this.formData.img这个img属性不是在表格中与表格中的填空项绑定的,而是图片上传完成后返回的一个图片名,再作为一个参数跟随表格数据一起发送到controller里面,从这里可以看出,vue里的变量可以先定义一个变量名,比如formData:{},但是里面的属性名可以不在VUE的data变量里定义,可以在表格里赋予,也可以在方法里赋予

第五天

//套餐分页查询,操作大同小异

/*清理多余的图片
	运用redis把上传成功的照片和存入数据库成功的图片名字存入redis,
	视频中讲的是创建两个集合,一个PIC,一个DBPIC
	但是实际上,只用一个集合也可以,并且理论上更加高效,不用对两个集合操作,也不用取两个集合差集,
	只需要在点确定的时候把一个集合中的该图片名字删除,集合中剩下的就是需要清理的图片,接下来把清理交给定时
	工具就可以了
*/

第六天

//使用POI对Excel文件读和写
/*
	注意点:
		1.点击下载按钮访问模板的请求路径
		downloadTemplate(){
                    window.location.href="../../template/ordersetting_template.xlsx";
                },
                这里注意路径往前面退两层,即../../
        2.预约数据的展示在完成serviceImpl功能时注意
        根据月份查询对应的预约设置数据
    	public List<Map> getOrderSettingByMonth(String date) {//格式:yyyy-MM
                String begin = date + "-1";//2019-6-1
                String end = date + "-31";//2019-6-31
                Map<String,String> map = new HashMap<>();
                map.put("begin",begin);
                map.put("end",end);
        //调用DAO,根据日期范围查询预约设置数据
        List<OrderSetting> list = orderSettingDao.getOrderSettingByMonth(map);
        List<Map> result = new ArrayList<>();
        if(list != null && list.size() > 0){
            for (OrderSetting orderSetting : list) {
                Map<String,Object> m = new HashMap<>();
                m.put("date",orderSetting.getOrderDate().getDate());//获取日期数字(几号)
                m.put("number",orderSetting.getNumber());
                m.put("reservations",orderSetting.getReservations());
                result.add(m);
            }
        }
        return result;
    }
    这里结果map的date的值注入的时候,注意调用的是Date类的getDate()方法,可以获取日期数字
*/

第七天

前端判断无法文件类型问题

const isXLSX = file.type === 'application/vnd.openxmlformats-														officedocument.spreadsheetml.sheet';
                    // return true;
if (isXLSX) {
                return true;
                    }
//预约人数设置
/*
	在进行预约设置的相关操作时,涉及到一个日期控件的使用,该控件会在页面一加载的时候进行日期初始化,
	该方法是initData(cur),一开始cur是没有值的,我们调用的时候可以给它赋值,没赋值它自己内部会new 一个	   日期出来,最后会查询出一个月的数据来
	另外,在进行预约人数设置的时候,ajax请求会发送两个参数,一个是我们输入的预约人数值,一个是当前的日期,
	可以看看这个弹出小窗口的相关代码
	this.$prompt('请输入可预约人数', '预约设置', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        inputPattern: /^[0-9]*[1-9][0-9]*$/,
                        inputErrorMessage: '只能输入正整数'
                    }).then(({ value }) => {
                        //发送ajax请求,将输入的数据提交到Controller
                        axios.post("/ordersetting/editNumberByDate.do",{
                            number:value,
       orderDate:this.formatDate(day.getFullYear(),day.getMonth()+1,day.getDate()) //日期
                        }).then((res) => {
                            if(res.data.flag){
                                this.initData(this.formatDate(day.getFullYear(), 													  day.getMonth() + 1, 1));
                                this.$message({
                                    type:'success',
                                    message:res.data.message
                                });
                            }else{
                                this.$message.error(res.data.message);
                            }
                        });
                    }).catch(() => {
                        this.$message({
                            type: 'info',
                            message: '取消输入'
                        });
                    });
*/
//移动端后台搭建+套餐展示

第八天

//体检套餐详情页
/*
	前端部分:
	healthmobile.js中的一个方法,用来获取url中的参数
	--------------------------------------
	function getUrlParam(paraName) {
        var url = document.location.toString();
        //alert(url);
        var arrObj = url.split("?");
        if (arrObj.length > 1) {
            var arrPara = arrObj[1].split("&");
            var arr;
            for (var i = 0; i < arrPara.length; i++) {
                arr = arrPara[i].split("=");
                if (arr != null && arr[0] == paraName) {
                    return arr[1];
                    }
            }
            return "";
        }else {
            return "";
        }
	}
	-----------------------------------
	查询套餐详情的时候,案例用的是映射文件形式,自己用的是注解形式,这里把两种都写在这里,以作对比
*/

映射文件形式

---------------------SetmealDao.xml文件-------------------------------
<?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="com.itheima.dao.SetmealDao">
    <resultMap id="baseResultMap" type="com.itheima.pojo.Setmeal">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="helpCode" property="helpCode"/>
        <result column="sex" property="sex"/>
        <result column="age" property="age"/>
        <result column="price" property="price"/>
        <result column="remark" property="remark"/>
        <result column="attention" property="attention"/>
        <result column="img" property="img"/>
    </resultMap>

    <resultMap id="findByIdResultMap" type="com.itheima.pojo.Setmeal" extends="baseResultMap">
        <!--多对多映射-->
        <collection
                property="checkGroups"
                ofType="com.itheima.pojo.CheckGroup"
                select="com.itheima.dao.CheckGroupDao.findCheckGroupById"
                column="id"
                >
        </collection>
    </resultMap>

  

    <!--根据套餐ID查询套餐详情(包含套餐基本信息、检查组信息、检查项信息)-->
    <select id="findById" parameterType="int" resultMap="findByIdResultMap">
        select * from t_setmeal where id = #{id}
    </select>
</mapper>

------------------------------------CheckGroupDao.xml文件--------------------------------
<?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="com.itheima.dao.CheckGroupDao">
    <resultMap id="baseResultMap" type="com.itheima.pojo.CheckGroup">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="helpCode" property="helpCode"/>
        <result column="sex" property="sex"/>
        <result column="remark" property="remark"/>
        <result column="attention" property="attention"/>
    </resultMap>

    <resultMap id="findByIdResultMap" type="com.itheima.pojo.CheckGroup" extends="baseResultMap">
        <!--检查组和检查项多对多关联查询-->
        <collection property="checkItems"
                     ofType="com.itheima.pojo.CheckItem"
                     column="id"
                     select="com.itheima.dao.CheckItemDao.findCheckItemById"
        ></collection>
    </resultMap>

    <!--根据套餐ID查询关联的检查组详情-->
    <select id="findCheckGroupById" parameterType="int" resultMap="findByIdResultMap">
        select * from t_checkgroup where id in (select checkgroup_id from t_setmeal_checkgroup where setmeal_id = #{setmeal_id})
    </select>
</mapper>
------------------------------CheckItemDao.xml文件---------------------------
    <select id="findCheckItemById" parameterType="int" resultType="com.itheima.pojo.CheckItem">
        select * from t_checkitem
        where id
  	    in (select checkitem_id from t_checkgroup_checkitem where checkgroup_id=#{id})
    </select>

注解形式

 	@Select("select * from t_setmeal where id = #{id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "code",property = "code"),
            @Result(column = "helpCode",property = "helpCode"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "age",property = "age"),
            @Result(column = "price",property = "price"),
            @Result(column = "remark",property = "remark"),
            @Result(column = "attention",property = "attention"),
            @Result(column = "img",property = "img"),
            @Result(
                    property =  "checkGroups",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = 												  								("com.zz.dao.CheckGroupDao.findCheckGroupById"))
            )
    })
    public Setmeal findById(int id);
--------------------------------------------------------------------------------
    @Select("select * from t_checkgroup where id in (select checkgroup_id from 						t_setmeal_checkgroup where setmeal_id = #{setmeal_id})")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "code",property = "code"),
            @Result(column = "helpCode",property = "helpCode"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "remark",property = "remark"),
            @Result(column = "attention",property = "attention"),
            @Result(
                    property = "checkItems",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = ("com.zz.dao.CheckItemDao.findCheckItemById"))
            )
    })
    public List<CheckGroup> findCheckGroupById(int id);
--------------------------------------------------------------------------
    @Select("select * from t_checkitem\n" +
            "        where id\n" +
            "  \t    in (select checkitem_id from t_checkgroup_checkitem where checkgroup_id=#{id})")
    public List<CheckItem> findCheckItemById(int id);
//短信发送
//注册----> 创建短信签名---> 创建短信模板---->创建accessKey ----> 复制工具类----> 调用工具类的发短信方法完成短信发送.

第九天

实现体检预约的前台页面效果

//完成orderInfo.html的页面
--------------------------实现点击发送验证码后倒计时30秒效果-----------------------------
-----先检查手机号格式是否正确
-----再来实现倒计时效果
            ---先将jquery对象转换为dom对象----------------------------
            |var doc2=$("#idDoc2")[0];   //转换jQuery对象为DOM对象   |
            |doc2.innerHTML="这是jQuery的第一个DOM对象"  	         |
            |//使用jQuery对象本身提供的get函数来返回指定集合位置的DOM对象 |
            |var doc2=$("#idDoc2").get(0);  					  |
            |doc2.innerHTML="这是jQuery的第二个DOM对象" 		     |
            -------------------------------------------------------
     //在按钮上显示30秒倒计时效果
       validateCodeButton = $("#validateCodeButton")[0];//锁定dom对象
       clock = window.setInterval(doLoop,1000);//定时器方法,可以实现每隔指定的时间调用指定的方法
      //发送ajax请求,为用户发送手机验证码
      axios.post("/validateCode/send4Order.do?telephone=" + telephone).then((res) => {
                            if(!res.data.flag){
                                //短信验证码发送失败
                                this.$message.error(res.data.message);
                            }
                        });
                    },

-------------可以看看doLoop里面定义的方法-----------------------------------
var clock = '';//定时器对象,用于页面30秒倒计时效果
var nums = 30;
var validateCodeButton;
//基于定时器实现30秒倒计时效果
function doLoop() {
    validateCodeButton.disabled = true;//将按钮置为不可点击
    nums--;
    if (nums > 0) {
        validateCodeButton.value = nums + '秒后重新获取';
    } else {
        clearInterval(clock); //清除js定时器
        validateCodeButton.disabled = false;
        validateCodeButton.value = '重新获取验证码';
        nums = 30; //重置时间
    }
}
---------------------下面看看选择时间的时候的那个日期控件------------------------
<input v-model="orderInfo.orderDate" type="text" class="picktime" readonly>
    上面的class注意是picktime
---再在下面定义日期控件的初始化
    <script>
            //日期控件
            var calendar = new datePicker();
            calendar.init({
                'trigger': '.picktime',/*按钮选择器,用于触发弹出插件*/
                'type': 'date',/*模式:date日期;datetime日期时间;time时间;ym年月;*/
                'minDate': getSpecifiedDate(new Date(),1),/*最小日期*/
                'maxDate': getSpecifiedDate(new Date(),30),/*最大日期*/
                'onSubmit': function() { /*确认时触发事件*/
                    //var theSelectData = calendar.value;
                },
                'onClose': function() { /*取消时触发事件*/ }
            });
        </script>

关于发送预约成功短信无法发送的问题

//调用工具类SMSUtils的时候,最后会有一个sendSmsResponse,用它获得获得短信返回值状态,
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
//		System.out.println(sendSmsResponse.getCode());
if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
			// 请求成功
			System.out.println("请求成功");
		}
//发现这里获得的状态是  isv.SMS_SIGNATURE_SCENE_ILLEGAL
/*
原因是 我的签名创建时选择的是验证码,所以只能与验证码的模板一起使用,当与短信通知或者其他模板一起使用时,就会报错。而申请通用签名,则必须要上传一些公司、APP、或者其他证件资料,比较麻烦,有需要的可以了解一下

还有别想着用验证码接口,给code变量传你想要的内容,短信接口调用时,做了一系列的验证,比如不能传中文,不能传太长的内容,不能发送频繁,等等。反正验证码接口最终发送的内容就是几个数字或几个字母,别想着发送一句话啥的。

比如 发送 尊敬的某某女士,今天是520 ,最终只能用 zunjing_de_moumou_发送一条,jintian_shi_520,发送一条,比较尴尬,想推送消息,还是要申请通用的签名和模板
*/

第十天

体检预约的后台代码

//OrderController代码
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private JedisPool jedisPool;
    @Reference
    private OrderService orderService;
    //在线体检预约
    @RequestMapping("/submit")
    public Result submit(@RequestBody Map map){
        String telephone = (String) map.get("telephone");
        //从Redis中获取保存的验证码
        String validateCodeInRedis = jedisPool.getResource().get(telephone + 												 RedisMessageConstant.SENDTYPE_ORDER);
        String validateCode = (String) map.get("validateCode");

        //将用户输入的验证码和Redis中保存的验证码进行比对
        if(validateCodeInRedis != null && validateCode != null && 								   validateCode.equals(validateCodeInRedis)){
            //如果比对成功,调用服务完成预约业务处理
            map.put("orderType", Order.ORDERTYPE_WEIXIN);//设置预约类型,分为微信预约、电话预约
            Result result = null;
            try{
                result = orderService.order(map);//通过Dubbo远程调用服务实现在线预约业务处理
            }catch (Exception e){
                e.printStackTrace();
                return result;
            }
            if(result.isFlag()){
                //预约成功,可以为用户发送短信
                try{
                    SMSUtils.sendShortMessage(SMSUtils.ORDER_NOTICE,telephone,(String) 						map.get("orderDate"));
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            return result;
        }else{
            //如果比对不成功,返回结果给页面
            return new Result(false, MessageConstant.VALIDATECODE_ERROR);
        }
    }
//OrderServiceImpl的代码-------比较复杂
/*
	先理清步骤:
	 	1.先判断当前预约日期是否有设置过预约设置,否则无法预约
	 	2.判断当前预约日期的orderSetting的可预约人数是否小于等于已预约人数,是就无法预约
	 	3.判断当前预约客户是否为会员,
	 		如果是,判断该会员是否重复预约,是就无法在此预约
	 		如果不是,自动把当前客户存入会员表
		4.在订单表新增一条订单表,并在预约设置更新预约人数
*/
@Service(interfaceClass = OrderService.class)
@Transactional
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderSettingDao orderSettingDao;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private OrderDao orderDao;
    //体检预约
    public Result order(Map map) throws Exception{
        //1、检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约
        String orderDate = (String) map.get("orderDate");//预约日期
        OrderSetting orderSetting= 										 						orderSettingDao.findByOrderDate(DateUtils.parseString2Date(orderDate));
        if(orderSetting == null){
            //指定日期没有进行预约设置,无法完成体检预约
            return new Result(false, MessageConstant.SELECTED_DATE_CANNOT_ORDER);
        }

        //2、检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约
        int number = orderSetting.getNumber();//可预约人数
        int reservations = orderSetting.getReservations();//已预约人数
        if(reservations >= number){
            //已经约满,无法预约
            return new Result(false,MessageConstant.ORDER_FULL);
        }

        //3、检查当前用户是否为会员,如果是会员检查用户是否重复预约(同一个用户在同一天预约了同一个套				餐),如果是重复预约则无法完成再次预约
        String telephone = (String) map.get("telephone");//获取用户页面输入的手机号
        Member member = memberDao.findByTelephone(telephone);
        if(member != null){
            //判断是否在重复预约
            Integer memberId = member.getId();//会员ID
            Date order_Date = DateUtils.parseString2Date(orderDate);//预约日期
            String setmealId = (String) map.get("setmealId");//套餐ID
            Order order = new Order(memberId, order_Date, Integer.parseInt(setmealId));
            //根据条件进行查询
            List<Order> list = orderDao.findByCondition(order);
            if(list != null && list.size() > 0){
                //说明用户在重复预约,无法完成再次预约
                return new Result(false,MessageConstant.HAS_ORDERED);
            }
        }else{
            //4、如果不是会员则自动完成注册
            member = new Member();
            member.setName((String) map.get("name"));
            member.setPhoneNumber(telephone);
            member.setIdCard((String) map.get("idCard"));
            member.setSex((String) map.get("sex"));
            member.setRegTime(new Date());
            memberDao.add(member);//自动完成会员注册
        }

        //5、进行预约,预约成功,更新当日的已预约人数
        Order order = new Order();
        order.setMemberId(member.getId());//设置会员ID
        order.setOrderDate(DateUtils.parseString2Date(orderDate));//预约日期
        order.setOrderType((String) map.get("orderType"));//预约类型
        order.setOrderStatus(Order.ORDERSTATUS_NO);//到诊状态
        order.setSetmealId(Integer.parseInt((String) map.get("setmealId")));//套餐ID
        orderDao.add(order);

        orderSetting.setReservations(orderSetting.getReservations() + 1);//设置已预约人数+1
        orderSettingDao.editReservationsByOrderDate(orderSetting);

        return new Result(true,MessageConstant.ORDER_SUCCESS,order.getId());//这里返回order		   的id,因为前端只要id就可以了
    }

十一天

/*登录
这里在前台发送请求过来后,在controller需要完成以下步骤
	1.从redis中取验证码和传过来的验证码做对比
	2.判断是否是会员,如果不是,直接存入会员表里
	3.把电话号码信息存入cookie中
	4.把会员信息存入redis,key是telephone
	
	不过这里要注意,这里只是存入了cookie,目前这个案例还没有取cookie,cookie的作用是把cookie带过来之后
	取出号码再从redis中取member信息,判断是否最近登录过

*/
@RestController
@RequestMapping("/member")
public class MemberController {
    @Autowired
    private JedisPool jedisPool;

    @Reference
    private MemberService memberService;

    //手机号快速登录
    @RequestMapping("/login")
    public Result login(HttpServletResponse response, @RequestBody Map map){
        String telephone = (String) map.get("telephone");
        String validateCode = (String) map.get("validateCode");
        //从Redis中获取保存的验证码
        String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisMessageConstant.SENDTYPE_LOGIN);
        if(validateCodeInRedis != null && validateCode != null && validateCode.equals(validateCodeInRedis)){
            //验证码输入正确
            //判断当前用户是否为会员(查询会员表来确定)
            Member member = memberService.findByTelephone(telephone);
            if(member == null){
                //不是会员,自动完成注册(自动将当前用户信息保存到会员表),这里注意这里的member是null,需要new一个出来
                member = new Member();
                member.setRegTime(new Date());
                member.setPhoneNumber(telephone);
                memberService.add(member);
            }
            //向客户端浏览器写入Cookie,内容为手机号
            Cookie cookie = new Cookie("login_member_telephone",telephone);
            cookie.setPath("/");//这里意味着只要访问这个项目地址就把这个cookie带上,如果是“/page”说明只有在访问“/localhost:port/page/**”下的页面时候才带上这个cookie
            cookie.setMaxAge(60*60*24*30);
            response.addCookie(cookie);
            //将会员信息保存到Redis
            String json = JSON.toJSON(member).toString();
            jedisPool.getResource().setex(telephone,60*30,json);
            return new Result(true,MessageConstant.LOGIN_SUCCESS);
        }else{
            //验证码输入错误
            return new Result(false, MessageConstant.VALIDATECODE_ERROR);
        }
    }
}


---------------------memberServiceImpl--------------------------------------
    //通过手机号查找会员信息
    public Member findByTelephone(String telephone) {
        return memberDao.findByTelephone(telephone);
    }

    //保存会员信息,这里要保证严谨,因为不知道前面是否存入过密码
    public void add(Member member) {
        String password = member.getPassword();
        if(password != null){
            //使用md5将明文密码进行加密
            password = MD5Utils.md5(password);
            member.setPassword(password);
        }
        memberDao.add(member);
    }

十二天

Spring Security权限控制

第一步,引入坐标

		<!--  权限控制-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
        </dependency>

第二步,配置spring-security.xml文件

	<!--配置哪些资源匿名可以访问(不登录也可以访问)-->
    <security:http security="none" pattern="/login.html"></security:http>
    <security:http security="none" pattern="/css/**"></security:http>
    <security:http security="none" pattern="/img/**"></security:http>
    <security:http security="none" pattern="/js/**"></security:http>
    <security:http security="none" pattern="/plugins/**"></security:http>
    <!--
        auto-config:自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页		   面
        use-expressions:是否使用spring security提供的表达式来描述权限
    -->
    <security:http auto-config="true" use-expressions="true">
        <security:headers>
            <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
            <security:frame-options policy="SAMEORIGIN"></security:frame-options>
        </security:headers>
        <!--配置拦截规则,/** 表示拦截所有请求-->
        <!--
            pattern:描述拦截规则
            asscess:指定所需的访问角色或者访问权限
        -->
        <!--只要认证通过就可以访问-->
        <security:intercept-url pattern="/pages/**"  access="isAuthenticated()" />

        <!--如果我们要使用自己指定的页面作为登录页面,必须配置登录表单.页面提交的登录表单请求是由框架负责			   处理-->
        <!--
            login-page:指定登录页面访问URL
        -->
        <!--
			login-processing-url="/login.do"
			一般这个配置完才去登录页面设置action的地址,两者必须是一样的,即登录页面把登录表单数据提交到			 action的地址之后,就会被拦截
		-->
        <security:form-login
                login-page="/login.html"
                username-parameter="username"
                password-parameter="password"
                login-processing-url="/login.do"
                default-target-url="/pages/main.html"
                authentication-failure-url="/login.html"></security:form-login>

        <!--
          csrf:对应CsrfFilter过滤器
          disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用		  (403)
		  因为在默认登录页面上其实有一个隐藏域,提交表单的时候会把隐藏域中的csrf对应的一串值带过去,代表			  这个页面是官方自带的,是安全的,而自己设置的登录页面没有这个值,security认为不安全,所以必须关		   闭
        -->
        <security:csrf disabled="true"></security:csrf>

        <!--
          logout:退出登录
          logout-url:退出登录操作对应的请求路径
          logout-success-url:退出登录后的跳转页面
        -->
        <security:logout logout-url="/logout.do"
                         logout-success-url="/login.html" invalidate-session="true"/>

    </security:http>

    <!--配置认证管理器-->
    <security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider user-service-ref="springSecurityUserService">
            <!--
                    配置一个具体的用户,后期需要从数据库查询用户
            <security:user-service>
                <security:user name="admin" password="{noop}1234" 										authorities="ROLE_ADMIN"/>
            </security:user-service>
            -->
            <!--指定度密码进行加密的对象-->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <!--配置密码加密对象-->
    <bean id="passwordEncoder"
          class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
	<!--  如果想要注解方式,需要在这里配置如下参数,但在这个项目,都可以省略,原因看解释方块
		<context:annotation-config></context:annotation-config>
    	<mvc:annotation-driven></mvc:annotation-driven>

    	<context:component-scan base-package="com.itheima.controller">							</context:component-scan>   

	-->

    <!--开启注解方式权限控制-->
    <security:global-method-security pre-post-annotations="enabled" />

解释方块

		<!--下面这个注解是 开启spring注解使用-->
		<context:annotation-config></context:annotation-config>

		<!--这个注解是 会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两		   个Bean,mvc三大组件中除视图解析器(InternalResourceViewResolver)的另外两大组件-->
    	<mvc:annotation-driven></mvc:annotation-driven>

		<!--这是配置扫描包,配置这个的时候,可将<context:annotation-config/>省去-->
    	<context:component-scan base-package="com.itheima.controller">							</context:component-scan> 

		<!--之所以在这个xml配置文件中上面这些参数都不用配置,是因为在springmvc.xml这个配置文件有代替这			些参数的配置。
		   springmvc.xml这个配置文件是配置dubbo相关设置的,里面有如下配置:
			1.<mvc:annotation-driven></mvc:annotation-driven>
			2.<dubbo:annotation package="com.zz" />批量扫描,代替<context:component-scan>
			然后上面也说了,配置了扫描包设置就可以省略<context:annotation-config/>
			
			所以上面这些参数设置在spring-security.xml中都可以省略
		-->

第三步,配置web.xml文件

<!--委派过滤器,用于整合其他框架-->
      <filter>
            <!--整合spring security时,此过滤器的名称固定springSecurityFilterChain-->
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      </filter>
	  <filter-mapping>
                <filter-name>springSecurityFilterChain</filter-name>
                <url-pattern>/*</url-pattern>
      </filter-mapping>
<!--这里省略了很多,比如解决post乱码问题的filter还有前端控制器,前端控制器加载resources里面的配置文件-->

第四步,使用数据库中用户信息进行权限控制,创建SpringSecurityUserService.java类,实现UserDetailsService接口,将这个类做为认证提供者

@Component
/*这里配置了Component之后,spring-security.xml文件中就不用配置<bean id="springSecurityUserService" class="com.zz.service.SpringSecurityUserService"></bean>
虽然xml文件中报红,但是实际没有问题
*/
public class SpringSecurityUserService implements UserDetailsService {
    //使用dubbo通过网络远程调用服务提供方获取数据库中的用户信息
    @Reference
    private UserService userService;

    //根据用户名查询数据库获取用户信息
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if(user == null){
            //用户名不存在
            return null;
        }

        List<GrantedAuthority> list = new ArrayList<>();

        //动态为当前用户授权
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            //遍历角色集合,为用户授予角色
            list.add(new SimpleGrantedAuthority(role.getKeyword()));
            Set<Permission> permissions = role.getPermissions();
            for (Permission permission : permissions) {
                //遍历权限集合,为用户授权
                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }

        org.springframework.security.core.userdetails.User securityUser =
        new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);

        return securityUser;
    }
}

十三天

第五步,方法的权限控制

 //删除检查项
    @PreAuthorize("hasAuthority('CHECKITEM_DELETE')")//权限校验
    @RequestMapping("/delete")
    public Result delete(Integer id){
        try{
            checkItemService.deleteById(id);
        }catch (Exception e){
            e.printStackTrace();
            //服务调用失败
            return new Result(false, MessageConstant.DELETE_CHECKITEM_FAIL);
        }
        return  new Result(true, MessageConstant.DELETE_CHECKITEM_SUCCESS);
    }

退出登录

<!--前台-->
			  <el-dropdown-item divided>
                                        <span style="display:block;">
                                            <a href="/logout.do">退出</a>
                                        </span>
              </el-dropdown-item>

十四天&十五天

<!-- -->
<!--
	这两天主要用百度的echart报表工具制作报表
	使用步骤如下:
	
		1.导入echart.js			-->
		<script src="../plugins/echarts/echarts.js"></script>
		
<!--	2.把需要用到的报表图从官网copy代码过来,在自己的页面使用,具体如下使用
		
			 为ECharts准备一个具备大小(宽高)的Dom 			-->

   	    <div id="main" style="width: 600px;height:400px;"></div>
        <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>

报表的使用很简单,有难度的是把数据库中的数据按照需要查出来并封装,这里最常用到的是list集合以及map集合

不同json格式对应不同封装数据方式,返回不同的数据类型

ReportController

@RestController
@RequestMapping("/report")
public class ReportController {
    @Reference
    private MemberService memberService;

    @Reference
    private SetmealService setmealService;

    /*
    *       {
    *           months:["xx","xx","xx"],
    *           memberCount:[xx,xx,xx]
    *       }
    *
    * */

    //会员数量折线图数据
    @RequestMapping("/getMemberReport")
    public Result getMemberReport(){
        Map<String,Object> map = new HashMap<>();
        List<String> months = new ArrayList();
        Calendar calendar = Calendar.getInstance();//获得日历对象,模拟时间就是当前时间
        //计算过去一年的12个月
        calendar.add(Calendar.MONTH,-12);//获得当前时间往前推12个月的时间
        for(int i=0;i<12;i++){
            calendar.add(Calendar.MONTH,1);//获得当前时间往后推一个月日期
            Date date = calendar.getTime();
            months.add(new SimpleDateFormat("yyyy.MM").format(date));
        }
        map.put("months",months);

        List<Integer> memberCount = memberService.findMemberCountByMonths(months);
        map.put("memberCount",memberCount);
        return new Result(true, MessageConstant.GET_MEMBER_NUMBER_REPORT_SUCCESS,map);
    }

    //套餐预约占比饼形图
    @RequestMapping("/getSetmealReport")
    public Result getSetmealReport(){
        //使用模拟数据测试使用什么样的java对象转为饼形图所需的json数据格式
        /*
        *   {
        *       setmealCount:[
        *           {name:"",value:xx},
        *           {name:"",value:xx}
        *       ],
        *       setmealNames:["xx","xx","xx"]
        *   }
        * */
        Map<String,Object> data = new HashMap<>();

        /*List<String> setmealNames = new ArrayList<>();
        setmealNames.add("体检套餐");
        setmealNames.add("孕前检查套餐");
        data.put("setmealNames",setmealNames);*/
        try{
            List<Map<String,Object>> setmealCount = setmealService.findSetmealCount();
            data.put("setmealCount",setmealCount);

            List<String> setmealNames = new ArrayList<>();
            for (Map<String, Object> map : setmealCount) {
                String name = (String) map.get("name");//套餐名称
                setmealNames.add(name);
            }

            data.put("setmealNames",setmealNames);
            return new Result(true,MessageConstant.GET_SETMEAL_COUNT_REPORT_SUCCESS,data);
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false,MessageConstant.GET_SETMEAL_COUNT_REPORT_FAIL);
        }
    }

    @Reference
    private ReportService reportService;

    //运营数据统计
    @RequestMapping("/getBusinessReportData")
    public Result getBusinessReportData(){
        try{
            Map<String,Object> data = reportService.getBusinessReportData();
            return new Result(true,MessageConstant.GET_BUSINESS_REPORT_SUCCESS,data);
        }catch (Exception e){
            return new Result(false,MessageConstant.GET_BUSINESS_REPORT_FAIL);
        }
    }

    //导出运营数据
    @RequestMapping("/exportBusinessReport")
    public Result exportBusinessReport(HttpServletRequest request, HttpServletResponse response){
        try{
            Map<String,Object> result = reportService.getBusinessReportData();
            //取出返回结果数据,准备将报表数据写入到Excel文件中
            String reportDate = (String) result.get("reportDate");
            Integer todayNewMember = (Integer) result.get("todayNewMember");
            Integer totalMember = (Integer) result.get("totalMember");
            Integer thisWeekNewMember = (Integer) result.get("thisWeekNewMember");
            Integer thisMonthNewMember = (Integer) result.get("thisMonthNewMember");
            Integer todayOrderNumber = (Integer) result.get("todayOrderNumber");
            Integer thisWeekOrderNumber = (Integer) result.get("thisWeekOrderNumber");
            Integer thisMonthOrderNumber = (Integer) result.get("thisMonthOrderNumber");
            Integer todayVisitsNumber = (Integer) result.get("todayVisitsNumber");
            Integer thisWeekVisitsNumber = (Integer) result.get("thisWeekVisitsNumber");
            Integer thisMonthVisitsNumber = (Integer) result.get("thisMonthVisitsNumber");
            List<Map> hotSetmeal = (List<Map>) result.get("hotSetmeal");
		 /*
            	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            	|	这里怎么样获得文件全路径要记得方法					  |
            	|					    							 |
            	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            */
            String filePath = request.getSession().getServletContext().getRealPath("template")+ File.separator+"report_template.xlsx";
            //基于提供的Excel模板文件在内存中创建一个Excel表格对象
            XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File(filePath)));
            //读取第一个工作表
            XSSFSheet sheet = excel.getSheetAt(0);

            XSSFRow row = sheet.getRow(2);
            row.getCell(5).setCellValue(reportDate);//日期

            row = sheet.getRow(4);
            row.getCell(5).setCellValue(todayNewMember);//新增会员数(本日)
            row.getCell(7).setCellValue(totalMember);//总会员数

            row = sheet.getRow(5);
            row.getCell(5).setCellValue(thisWeekNewMember);//本周新增会员数
            row.getCell(7).setCellValue(thisMonthNewMember);//本月新增会员数

            row = sheet.getRow(7);
            row.getCell(5).setCellValue(todayOrderNumber);//今日预约数
            row.getCell(7).setCellValue(todayVisitsNumber);//今日到诊数

            row = sheet.getRow(8);
            row.getCell(5).setCellValue(thisWeekOrderNumber);//本周预约数
            row.getCell(7).setCellValue(thisWeekVisitsNumber);//本周到诊数

            row = sheet.getRow(9);
            row.getCell(5).setCellValue(thisMonthOrderNumber);//本月预约数
            row.getCell(7).setCellValue(thisMonthVisitsNumber);//本月到诊数

            int rowNum = 12;
            for(Map map : hotSetmeal){//热门套餐
                String name = (String) map.get("name");
                Long setmeal_count = (Long) map.get("setmeal_count");
                BigDecimal proportion = (BigDecimal) map.get("proportion");
                row = sheet.getRow(rowNum ++);
                row.getCell(4).setCellValue(name);//套餐名称
                row.getCell(5).setCellValue(setmeal_count);//预约数量
                row.getCell(6).setCellValue(proportion.doubleValue());//占比
            }

            //使用输出流进行表格下载,基于浏览器作为客户端下载
            /*
            	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            	|	如果直接用OutputStream代表着只是在服务器的磁盘上写文件,|
            	|	要想把输出流写回浏览器,就需要用response获得输出流,	  |
            	|	并且要记得设置ContentType和Header类型				  |
            	|	然后用excel.write(输出流)就可把流文件写回去     	 |
            	|	关闭各种流不要忘了								  |
            	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            */
            OutputStream out = response.getOutputStream();
            response.setContentType("application/vnd.ms-excel");//代表的是Excel文件类型
            response.setHeader("content-Disposition", "attachment;filename=report.xlsx");//指定以附件形式进行下载
            excel.write(out);

            out.flush();
            out.close();
            excel.close();
            return null;
        }catch (Exception e){
            return new Result(false,MessageConstant.GET_BUSINESS_REPORT_FAIL);
        }
    }

}

dao文件的sql编写,很值得学习

<!--热门套餐查询仔细看看-->

@Select("select s.name, count(o.id) setmeal_count ,count(o.id)/(select count(id) from t_order) proportion\n" +
            "          from t_order o inner join t_setmeal s on s.id = o.setmeal_id\n" +
            "          group by o.setmeal_id\n" +
            "          order by setmeal_count desc limit 0,4")
public List<Map> findHotSetmeal();

自己模块阶段bug

百度地图模块知识点

//如何在html中嵌入地图其实很简单
/*
	1.先去百度地图申请好密匙,要记得先认证好个人开发者
	
	2.引入百度地图apiwenjian
	<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=您的密钥">	</script>
	//给地图设置样式
	<style>
		#myMap{
                height: 450px;
                width: 100%;
                overflow: hidden;
                font-family: "微软雅黑";
                border:1px solid green;
            }
	</style>
	
	3.创建地图容器元素
	<div id="myMap">hello</div>  
	
	4.定义一个初始化地图的方法
	baiduMap() {
                    var map = new BMap.Map("myMap");//创建地图实例
                    
                    //var point = new BMap.Point(114.31, 30.52);
                    //map.centerAndZoom(point, 15);另一种地图初始化方法
                    
                    map.centerAndZoom("武汉市",11);//地图初始化,同时设置地图展示级别
                    map.enableScrollWheelZoom(true); //开启滑轮
                    
                    var point = new BMap.Point(114.628,30.875);
                    var marker = new BMap.Marker(point);  // 创建标注
                    map.addOverlay(marker);               // 将标注添加到地图中
                    marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
					//给标注点加上文字
                    var label = new BMap.Label("好地方哦",{offset:new BMap.Size(20,-10)});
                    marker.setLabel(label);

                }
    5.加载页面的时候调用这个方法即可

*/

实现从数据库查找地址并且在地图上显示标注点

<!--
	分析:要想从数据库拿数据并显示,说明要在初始化页面的时候就要发请求,并且在拿到了数据后才在地图上显示,		这里就要求这个请求是同步发送的,不然还没拿到数据地图已经初始化完成了,标注点也没有显示出来。

	所以,使用$.ajax来发送请求,可以实现同步,而axios只能是异步发送
		
-->
<body onload="init()">
	<div id="l-map"></div>
</body>

<script type="text/javascript">
	// 百度地图API功能
	var map = new BMap.Map("l-map");
	// var point = new BMap.Point(114.4060230, 30.7123300);
	// map.centerAndZoom(point,10);
	map.centerAndZoom("武汉市",11);

	//根据浏览器定位当前位置
	function init() {
		load();
	}
	//加载分店位置
	function load() {
		map.enableScrollWheelZoom(true);
		var index = 0;
		var myGeo = new BMap.Geocoder();
		var adds = [];
		var addNames=[];

		$.ajax({
			type:"POST",
			url:"/address/findAllMaps.do",
			// data:JSON.stringify(param),
			async: false,
			contentType:"application/json;charset=utf-8",
			success: function (data) {
				// data = res.rows;
				// data = res;
				for(var x=0;x<data.length;x++){
					adds.push(new BMap.Point(data[x].lng,data[x].lat));
					addNames.push(data[x].address);
				}
			}
		});

		for(var i = 0; i<adds.length; i++){
			var marker = new BMap.Marker(adds[i]);
			map.addOverlay(marker);
			// marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
			marker.setLabel(new BMap.Label(addNames[i],{offset:new BMap.Size(20,-10)}));
		}
		
	}
</script>

百度地图关键字提示

<div class="filter-container">
     <el-input id="suggestId" name="address_detail" placeholder="请输入要查询的地址" v-				   model="address_detail"  style="width: 400px;"></el-input>
</div>

<script>
    <!--将下面这个方法定义在适当的位置-->
	createMap(){
                this.$nextTick(function () {
                    var th = this
                    // 创建Map实例
                    var map = new BMap.Map("allmap");
                    map.enableScrollWheelZoom();//准许滑轮
                    map.centerAndZoom("武汉市",11);

                    //建立一个自动完成的对象
                    var ac = new BMap.Autocomplete({"input": "suggestId", "location": map})

                    var myValue;
                    ac.addEventListener("onconfirm", function (e) {//鼠标点击下拉列表后的事件
                        console.log(e)
                        var _value = e.item.value;
                        myValue = _value.province + _value.city + _value.district + _value.street + _value.business;
                        th.address_detail = myValue;
                        setPlace();
                    });

                    function setPlace() {

                        map.clearOverlays();    //清除地图上所有覆盖物
                        function myFun() {
                            th.userlocation = local.getResults().getPoi(0).point;    //获取第一个智能搜索的结果
                            temp = th.userlocation;
                            map.centerAndZoom(th.userlocation, 15);
                            map.addOverlay(new BMap.Marker(th.userlocation));    //添加标注
                        }

                        var local = new BMap.LocalSearch(map, { //智能搜索
                            onSearchComplete: myFun
                        });
                        // alert("666");
                        local.search(myValue);

                    }

                    // 百度地图API功能
                    function G(id) {
                        return document.getElementById(id);
                    }
                })
            },
</script>

设计地址表的时候参数类型

//因为经纬度都是精确到小数点后67位的,所以得用DECIMAL(10,7)类型,而POJO类用String类对应
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值