新增收货地址

收货地址管理页面

image-20230808193330806

点击新增收货地址按钮,出现新的页面,地址信息编辑表单

image-20230808193413631

各功能的开发顺序

收货地址模块的功能:列表的展示、修改、删除、设置默认、新增收货地址

功能模块的开发顺序:新增收货地址-》列表展示-》设置默认收货地址-》删除收货地址-》修改收货地址

数据库表的创建

image-20230808194228462

收货地址实体类的创建

创建收货地址实体类com.bang.store.pojo.Address,继承自BasePojo基类,因为其同样含有四个公共字段

属性名与数据表名一致,只是注意数据库字段一般命名方式为xx_xx,而java采用驼峰命名法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 收货地址实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address extends BasePojo{
Integer aid;
Integer uid;
String name;
String provinceName;
String provinceCode;
String cityName;
String cityCode;
String areaName;
String areaCode;
String zip;
String address;
String phone;
String tel;
String tag;
Integer isDefault;

}

持久层

规划执行的SQL语句

新增收货地址本质上是将表单数据插入对应数据库表中,对应插入语句

1
insert into t_address(uid,name,province_name,province_code,city_name,city_code,area_name,area_code,zip,address,phone,tel,tag,is_default,created_user,created_time,modified_user,modified_time) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);

各个平台用户收货地址的保存是有上限的,在这里我们规定每个用户最多只能有3条(便于测试,实际上允许的地址数据会多很多)地址数据, 所以总体逻辑发生改变,即插入数据之前都需判断当前用户地址数目

本质上为依据用户id(uid)查询对应数据条数

1
select count(*) from t_address where uid=?;

接口和抽象方法

创建一个新的接口AddressMapper,在该接口中定义上述两个sql语句对应的抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 收货地址模块的mapper接口
*/
public interface AddressMapper {

/**
* 插入用户收货地址到数据库
* @param address 用户地址数据
* @return 受影响的行数
*/
Integer insert(Address address);

/**
* 查询当前用户收货地址条数
* @param uid 用户uid
* @return 用户收货地址条数
*/
Integer countByUid(Integer uid);
}

配置SQL映射

resource/mapper下创建地址映射文件Address.xml

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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bang.store.mapper.AddressMapper">

<resultMap id="addressPojoMap" type="com.bang.store.pojo.Address">
<id column="uid" property="uid"/>
<result column="province_name" property="provinceName"/>
<result column="province_code" property="provinceCode"/>
<result column="city_name" property="cityName"/>
<result column="city_code" property="cityCode"/>
<result column="area_name" property="areaName"/>
<result column="area_code" property="areaCode"/>
<result column="is_default" property="isDefault"/>
<result property="createUser" column="create_user"/>
<result property="createTime" column="create_time"/>
<result property="modifiedUser" column="modified_user"/>
<result property="modifiedTime" column="modified_time"/>
</resultMap>



<select id="countByUid" resultType="int">
select count(*) from t_address where uid=#{uid};
</select>

<!-- useGeneratedKeys="true" keyProperty="uid" 开启某个字段作为主键并值自动递增,并指明字段名称 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="aid">
insert into t_address(uid,name,province_name,province_code,city_name,city_code,
area_name,area_code,zip,address,phone,tel,tag,is_default,created_user,created_time,modified_user,modified_time)
values(#{uid},#{name},#{provinceName},#{provinceCode},#{cityName},#{cityCode},
#{areaName},#{areaCode},#{zip},#{address},#{phone},#{tel},#{tag},#{isDefault}
,#{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime});
</insert>
</mapper>

单元测试

test/java下创建com.bang.store.mapper.AddressMapperTest.java

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
package com.bang.store.mapper;


import com.bang.store.pojo.Address;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class AddressMapperTest {

@Resource
AddressMapper addressMapper;

@Test
public void countByUid(){
Integer count = addressMapper.countByUid(1);
System.out.println("当前用户地址数目:"+count);
}

@Test
public void insert(){
Address address = new Address();
address.setUid(1);
address.setProvinceName("安徽省");

Integer rows = addressMapper.insert(address);
System.out.println(rows);
}
}

业务层

规划异常

如果用户插入的是第一条收货地址,需要将当前地址设置为默认的收货地址(即当前地址的is_default字段设置为1)。如果查询到的结果大于3,这是需要抛出业务层的异常AddressCountLimit表明单个用户插入地址数据已达上限

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
package com.bang.store.service.ex;

/**
* 单个用户地址数目超过上限异常
*/
public class AddressCountLimitException extends ServiceException{
public AddressCountLimit() {
super();
}

public AddressCountLimit(String message) {
super(message);
}

public AddressCountLimit(String message, Throwable cause) {
super(message, cause);
}

public AddressCountLimit(Throwable cause) {
super(cause);
}

protected AddressCountLimit(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

地址数据插入过程的异常,InsertException在之前用户信息的功能模块中已经定义过了

接口和抽象方法

创建地址业务逻辑接口IAddressService,在其中定义抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 收货地址业务层接口
*/
public interface IAddressService {
/**
* 新增收货地址
* @param uid 用户id
* @param username 用户姓名
* @param address 用户地址数据
*/
void addAddress(Integer uid, String username, Address address);
}

抽象方法实现

创建接口实现类,AddressServiceImpl,在其中实现接口抽象方法

在配置文件application.properties文件中定义收货地址数量上限

1
user.address.max-count:3

Spring读取配置文件数据方法

1
2
@Value("${user.address.max-count}")
private Integer maxCount;

业务逻辑

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
/**
* 收货地址业务层实现类
*/
@Service
public class AddressServiceImpl implements IAddressService {
@Resource
AddressMapper addressMapper;

//地址上限设置在application.properties配置文件里
@Value("${user.address.max-count}")
private Integer maxCount;
@Override
public void addAddress(Integer uid, String username, Address address) {
//1.查询当前用户拥有地址数目
int count = addressMapper.countByUid(uid);
//超出地址上限,报异常
if(count>maxCount){
throw new AddressCountLimitException("收货地址数目超出规定上限");
}
//首条收货地址设置为默认收货地址
if(count==0){
address.setIsDefault(1);
}
address.setUid(uid);
address.setCreatedUser(username);
address.setCreatedTime(new Date());
address.setModifiedUser(username);
address.setModifiedTime(new Date());
//插入地址数据
Integer rows = addressMapper.insert(address);
if(rows!=1){
throw new InsertException("地址数据插入未知异常");
}

}
}

单元测试

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
package com.bang.store.service;

import com.bang.store.pojo.Address;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
@Autowired
IAddressService addressService;

@Test
public void addAddress(){
Integer uid = 2;
String username = "孙权";
Address address = new Address();
address.setUid(uid);
address.setName("王伟");

addressService.addAddress(uid,username,address);
}
}

控制层

异常处理

业务层抛出的收货地址数目大于规定最大阈值的异常处理,在控制层基类BaseController中定义对应的逻辑

1
2
3
4
else if (e instanceof AddressCountLimitException) {
result.setState(7000);
result.setMessage("收获地址数目超出上限");
}

设计请求

1
2
3
4
request url: /address/add_new_address
request method: POST
request params: Address address,HttpSession session
response data: new JsonResult<Void>

处理请求

新建收货地址控制层类AddressController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RestController
@RequestMapping("/address")
public class AddressController extends BaseController{

@Autowired
IAddressService addressService;

@RequestMapping("/add_new_address")
public JsonResult<Void> addAddress(Address address, HttpSession session){
//获取uid和用户名
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
//调用业务层,插入地址数据
addressService.addAddress(uid,username,address);
return new JsonResult<>(OK,"新增收货地址成功");
}
}

前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
$("#btn-add-new-address").click(function (){
$.ajax({
url: "/address/add_new_address"
,type: "POST"
,data: $("#form-add-new-address").serialize()
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
alert("地址保存成功");
}else{
alert("地址保存失败 "+data.message);
}
}
,error:function (xmh){
alert("地址保存失败"+xmh.status);
}
});
});
</script>

获取省市区列表

省市区列表数据库表的创建

创建数据库存储省市区列表数据

1
2
3
4
5
6
7
CREATE TABLE t_dict_district (
id int(11) NOT NULL AUTO_INCREMENT,
parent varchar(6) DEFAULT NULL,
code varchar(6) DEFAULT NULL,
name varchar(16) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

image-20230809192240718

数据库字段说明

  • parent表示父区域代码号
  • code表示区域自己的代码号
  • name区域名称

省市区列表实体类的创建

创建对应的实体类com.bang.store.pojo.district

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 省市区地址实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class District {
Integer id;
String parent;
String code;
String name;
}

省市区列表持久层

规划执行的SQL语句

查询语句,根据父代号进行查询

1
select * from t_dict_district where parent=? order by code ASC;

接口和抽象方法

创建新的接口DistrictMapper,在其中定义对应的抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 省市区地址持久层接口
*/
public interface DistrictMapper {

/**
* 根据父代号查询所有的省市区列表
* @param parent 父代号
* @return 省市区列表
*/
List<District> findByParent(String parent);
}

配置SQL映射

resource/mapper文件夹下创建DistrictMappper.xml文件,编写对应的SQL映射

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bang.store.mapper.DistrictMapper">
<select id="findByParent" resultType="com.bang.store.pojo.District">
select * from t_dict_district where parent=#{parent} order by code ASC;
</select>
</mapper>

单元测试

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
package com.bang.store.mapper;

import com.bang.store.pojo.District;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DistrictMapperTest {

@Resource
DistrictMapper districtMapper;

@Test
public void findByParent(){
String parent="86";
List<District> districtList = districtMapper.findByParent(parent);
for (District district : districtList) {
System.out.println(district);
}
}
}

省市区列表持久层

规划异常

此功能无异常需要处理

抽象接口和方法

新建省市区列表业务层接口IDistrictService,在其中创建对应的抽象方法

1
2
3
4
5
6
7
8
9
10
11
/**
* 省市区数据业务层接口
*/
public interface IDistrictService {
/**
* 根据父代号查询省市区信息列表
* @param parent 父代号
* @return 省市区信息列表
*/
List<District> getByParent(String parent);
}

抽象方法实现

创建业务层接口实现类DistrictServiceImpl,在其中实现接口中的抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class DistrictServiceImpl implements IDistrictService {
@Resource
DistrictMapper districtMapper;
@Override
public List<District> getByParent(String parent) {
//调用持久层查询数据列表
List<District> districtList = districtMapper.findByParent(parent);
/**
* 在进行网络数据传输时,为了避免无效数据的传递,可以将无效数据设置为null,
* 这样一方面可以节省流量另一方面可以提高效率
*
* 在此问题中,依据parent代号查询其下的所有省市区信息,真正有效字段其实只有code和name,一次其他字段可以认为i设置为null
*/
for (District district : districtList) {
district.setId(null);
district.setParent(null);
}
return districtList;
}
}

单元测试

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
package com.bang.store.service;

import com.bang.store.pojo.District;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DistrictServiceTest {
@Autowired
IDistrictService districtService;

@Test
public void getByParent(){
String parent = "86";
List<District> districts = districtService.getByParent(parent);
for (District district : districts) {
System.out.println(district);
}
}
}

省市区列表控制层

设计请求

1
2
3
4
request url: /district/
request method: GET
request params: String parent
response data: new JsonResult<Lsit<District>>

请求处理

创建新的控制层类DistrictController,在里面编写对应的请求处理方法

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
package com.bang.store.controller;

import com.bang.store.pojo.District;
import com.bang.store.service.IDistrictService;
import com.bang.store.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/district")
public class DistrictController extends BaseController{

@Autowired
IDistrictService districtService;

//以/district开头的请求url均会被拦截到该方法
//url=/district或者url=/district/均有效
@RequestMapping({"/",""})
public JsonResult<List<District>> getByParent(String parent){
List<District> districtList = districtService.getByParent(parent);
return new JsonResult<>(OK,"省市区信息获取成功",districtList);
}
}

省市区列表前端页面

前一个版本省市区信息是保存在前端页面的js文件中,通过js代码获取的

1
2
<script type="text/javascript" src="../js/distpicker.data.js"></script>
<script type="text/javascript" src="../js/distpicker.js"></script>

现将这两行代码注释掉,让省市区数据信息依靠后端接口获取

检查前端页面在提交表单数据省市区数据时是否有相关的name属性和id属性

获取省市区名称

依据省市区代码获取对应的省市区名称

省市区名称持久层

规划执行的SQL语句

依据省市区code查询对应省市区的name,本质为一条查询语句

1
select name from t_dict_district where code=?;

接口和抽象方法

1
2
3
4
5
6
/**
* 根据省市区代号查询对应的名称
* @param code 省市区代号
* @return 省市区名称
*/
String findNameByCode(String code);

配置SQL映射

1
2
3
<select id="findNameByCode" resultType="java.lang.String">
select name from t_dict_district where code=#{code};
</select>

单元测试

1
2
3
4
5
@Test
public void findNameByCode(){
String name = districtMapper.findNameByCode("110000");
System.out.println(name);
}

省市区名称业务层

无特定的异常需要处理,所以跳过规划异常

接口和抽象方法

1
2
3
4
5
6
/**
* 依据省市区代码获取对应名称
* @param code 省市区号码
* @return 省市区名称
*/
String getNameByCode(String code);

抽象方法实现

1
2
3
4
5
@Override
public String getNameByCode(String code) {
String name = districtMapper.findNameByCode(code);
return name;
}

单元测试

1
2
3
4
5
@Test
public void getNameByCode(){
String name = districtService.getNameByCode("120000");
System.out.println(name);
}

新增收货地址业务层的优化

用户新增收货地址,前端页面只会向后端传递省市区的代码,所以业务层在调用持久层接口将数据存入数据库时,需要调用IDistrictService接口中的getNameByCode来获取对应省市区名称,再存入数据库

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
/**
* 收货地址业务层实现类
*/
@Service
public class AddressServiceImpl implements IAddressService {
@Resource
AddressMapper addressMapper;
//地址业务层接口需要依赖省市区业务层接口
@Autowired
IDistrictService districtService;

//地址上限设置在application.properties配置文件里
@Value("${user.address.max-count}")
private Integer maxCount;
@Override
public void addAddress(Integer uid, String username, Address address) {
//1.查询当前用户拥有地址数目
int count = addressMapper.countByUid(uid);
//超出地址上限,报异常
if(count>maxCount){
throw new AddressCountLimitException("收货地址数目超出规定上限");
}
//首条收货地址设置为默认收货地址
if(count==0){
address.setIsDefault(1);
}
address.setUid(uid);
address.setCreatedUser(username);
address.setCreatedTime(new Date());
address.setModifiedUser(username);
address.setModifiedTime(new Date());

//依据前端反馈的省市区号码获取对应省市区名称
String provinceName = districtService.getNameByCode(address.getProvinceCode());
String cityName = districtService.getNameByCode(address.getCityCode());
String areaName = districtService.getNameByCode(address.getAreaCode());
address.setProvinceName(provinceName);
address.setCityName(cityName);
address.setAreaName(areaName);

//插入地址数据
Integer rows = addressMapper.insert(address);
if(rows!=1){
throw new InsertException("地址数据插入未知异常");
}

}
}

获取省市区前端页面

addAddress.html页面中编写对应的省市区展示,根据用户不同的选择将对应的省市区信息填充到对应的下拉列表

编写相关事件代码

整体前端页面的逻辑

  1. 用户点击新增收货地址按钮
  2. 出现地址信息表单页面,触发事件,自动将86(代表中国地区编号)发送后端,请求省份信息列表,填充到省份下拉列表,此时城市和区县下拉列表为只存在默认选项
  3. 省份下拉列表值发生改变,触发事件,自动向后端发送请求(携带当前选中省份号码),请求该省份的所有城市信息列表,填充到城市下拉列表
  4. 城市下拉列表发生改变,出发事件,自动向后端发送请求(携带当前选中城市号码),请求该城市的所有区县信息列表,填充到区县下拉列表
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
<script>
//每个下拉列表的默认选项
//注意:value属性非常重要,实际传给后端的值就是value属性值,这里将其定义为对应省市区的代码编号
let defaultOption = "<option value='0'>---- 请选择 ----</option>"
$(document).ready(function () {
showProvinceList();//外部定于对应的方法
//城市下拉列表添加对应子标签 option子标签
$("#city-list").append(defaultOption);
//区域下拉列表添加对应子标签 option子标签
$("#area-list").append(defaultOption);
})

//省的下拉列表数据展示
function showProvinceList(){
$("#province-list").append("<option value='0'>---- 请选择省/直辖市 ----</option>")
$.ajax({
url: "/district/"
,type: "GET"
,data: "parent=86"
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
//后端传回数据是list列表
let provinceList = data.data;
for(let i=0;i<provinceList.length;i++){
$("#province-list").append("<option value='"+provinceList[i].code+"'>"+provinceList[i].name+"</option>")
}
}else{
alert("省份数据获取失败 "+data.message);
}
}
,error:function (xmh){
alert("省份数据获取过程中发生未知错误"+xmh.status);
}
});
}
/**
* change()函数用于监听某个空间是否发生改变,一旦发生改变,触发事件,执行对应函数
*/
//省的下拉列表如果发生改变,会向后端服务器发送请求查询对应省下的所有市数据列表,并展示在对应的下拉列表
$("#province-list").change(function (){
//清空城市和区县下拉列表中所有内容
$("#city-list").empty();
$("#area-list").empty();
//填充默认值
$("#city-list").append("<option value='0'>---- 请选择市 ----</option>")
$("#area-list").append("<option value='0'>---- 请选择区县 ----</option>")
if($("#province-list").val()==0) return; //默认选项直接返回
$.ajax({
url: "/district/"
,type: "GET"
,data: "parent="+$("#province-list").val()
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
//后端传回数据是list列表
let cityList = data.data;
for(let i=0;i<cityList.length;i++){
$("#city-list").append("<option value='"+cityList[i].code+"'>"+cityList[i].name+"</option>")
}
}else{
alert("城市数据获取失败 "+data.message);
}
}
,error:function (xmh){
alert("城市数据获取过程中发生未知错误"+xmh.status);
}
});
})

//城市的下拉列表发生改变,会向后端服务器发送请求,查询对应市下面的区县信息列表,并展示在对应的下拉列表
$("#city-list").change(function (){
//清空区县下拉列表中所有的原始子标签
$("#area-list").empty();
//填充默认值
$("#area-list").append("<option value='0'>---- 请选择区县 ----</option>")
//选择默认无效项,直接返回
if($("#city-list").val()==0) return;
$.ajax({
url: "/district/"
,type: "GET"
,data: "parent="+$("#city-list").val()
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
//后端传回数据是list列表
let areaList = data.data;
for(let i=0;i<areaList.length;i++){
$("#area-list").append("<option value='"+areaList[i].code+"'>"+areaList[i].name+"</option>")
}
}else{
alert("区县数据获取失败 "+data.message);
}
}
,error:function (xmh){
alert("区县数据获取过程中发生未知错误"+xmh.status);
}
});
})
$("#btn-add-new-address").click(function (){
$.ajax({
url: "/address/add_new_address"
,type: "POST"
,data: $("#form-add-new-address").serialize()
,dataType: "JSON"
,success: function (data){
if(data.state == 200){
alert("地址保存成功");
}else{
alert("地址保存失败 "+data.message);
}
}
,error:function (xmh){
alert("地址保存失败"+xmh.status);
}
});
});
</script>