6. Added receipt address
1. New Receipt Address-Database Table Creation
CREATE TABLE t_address ( aid INT AUTO_INCREMENT COMMENT 'Receipt address id', uid INT COMMENT 'Owned User id', name VARCHAR(20) COMMENT 'Consignee Name', province_name VARCHAR(15) COMMENT 'province-Name', province_code CHAR(6) COMMENT 'province-Administrative Code', city_name VARCHAR(15) COMMENT 'city-Name', city_code CHAR(6) COMMENT 'city-Administrative Code', area_name VARCHAR(15) COMMENT 'area-Name', area_code CHAR(6) COMMENT 'area-Administrative Code', zip CHAR(6) COMMENT 'Postal Code', address VARCHAR(50) COMMENT 'Detailed address', phone VARCHAR(20) COMMENT 'Mobile phone', tel VARCHAR(20) COMMENT 'Fixed line', tag VARCHAR(6) COMMENT 'Label', is_default INT COMMENT 'Default or not:0-No default, 1-default', created_user VARCHAR(20) COMMENT 'Creator', created_time DATETIME COMMENT 'Creation Time', modified_user VARCHAR(20) COMMENT 'Modifier', modified_time DATETIME COMMENT 'Modification Time', PRIMARY KEY (aid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. Add Receipt Address - Create Entity Class
package com.jiabowen.store.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor /**Receipt Address Entity Class*/ public class Address extends BaseEntity { private Integer aid; private Integer uid; private String name; private String provinceName; private String provinceCode; private String cityName; private String cityCode; private String areaName; private String areaCode; private String zip; private String address; private String phone; private String tel; private String tag; private Integer isDefault; }
3. New Receipt Address - Persistence Layer
3.1 Sequence of development of each function
Current Receipt Address Module: List Display, Modify, Delete, Set Default, Add Receipt Address. Order of development: Add harvest address - List display - Set default harvest address - Modify delivery address
3.2 Planning for SQL statements to be executed
1. Corresponding insert statements:
insert into t_address (except aid List of Outer Fields) values(Field Value List)
2. A user's harvest address specifies that a maximum of 20 data corresponds to each other, and queries are made before inserting user data. An exception to the logical request for the receipt address
select count(*) from t_address where uid = ?
3.3 Interfaces and Abstract Methods
Create an interface Address in which to define the above two Sql statement abstract method mappings.
/** * Insert the user's receipt address * @param address Receipt Address Data * @return Number of rows affected */ Integer insert(Address address); /** * Count the number of receipt addresses based on the user's id * @param uid User's id * @return Total number of receipt addresses for the current user */ Integer countByUid(Integer uid);
3.4 Configure SQL Mapping
Create an AddressMapper.xml Mapping file, add abstract methods to this file
<?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.jiabowen.store.mapper.AddressMapper"> <resultMap id="AddressEntityMap" type="com.jiabowen.store.entity.Address"> <id column="aid" property="aid"/> <result column="province_code" property="provinceCode"/> <result column="province_name" property="provinceName"/> <result column="city_code" property="cityCode"/> <result column="city_name" property="cityName"/> <result column="area_code" property="areaCode"/> <result column="area_name" property="areaName"/> <result column="is_default" property="isDefault"/> <result column="created_user" property="createdUser"/> <result column="created_time" property="createdTime"/> <result column="modified_user" property="modifiedUser"/> <result column="modified_time" property="modifiedTime"/> </resultMap> <insert id="insert"> 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> <select id="countByUid" resultType="java.lang.Integer"> select count(*) from t_address where uid = #{uid} </select> </mapper>
Testing mapper layer code
@Test public void insert(){ Address address = new Address(); address.setUid(29); address.setName("Zhang San"); address.setPhone("11122233344"); System.out.println(addressMapper.insert(address)); } @Test public void countByUid(){ Integer count = addressMapper.countByUid(29); System.out.println(count); }
4. New Receipt Address-Business Layer
4.1 Planning Exceptions
( If the user is inserting the user's address for the first time, the rule is that when the user inserts the first address, the default shipping address is based on the current address, and if the total statistic is 0, the is_of the current address is The default value is set to 1. A query statistic with a result of 0 does not represent an exception.
( The query result is greater than 20, which requires throwing the AddressCountLimitException exception for business control. Create this exception yourself.
public class AddressCountLimitException extends ServiceException { //... }
4.2 Interfaces and Abstract Methods
1. Create an IAddressService interface that defines an abstract method of business
/** * Receipt Address Business Layer Interface */ public interface IAddressService { void addNewAddress(Integer uid, String username, Address address); }
2. Create an AddressServiceImpl implementation class to implement abstract methods in interfaces
public class AddressServiceImpl implements IAddressService { @Autowired private AddressMapper addressMapper; @Value("${user.address.max-Count}") private Integer maxCount; @Override public void addNewAddress(Integer uid, String username, Address address) { //Call the method of harvesting address statistics Integer count = addressMapper.countByUid(uid); if (count >= maxCount){ throw new AddressCountLimitException("User receipt address exceeds maximum"); } //Set uid isdefault address.setUid(uid); Integer isdefault = count == 0 ? 1 : 0;//1 means default, 0 means not default address.setIsDefault(isdefault); //Complete Log address.setCreatedUser(username); address.setModifiedUser(username); address.setCreatedTime(new Date()); address.setModifiedTime(new Date()); //Method of inserting receipt address Integer rows = addressMapper.insert(address); if (rows != 1){ throw new InsertException("Inserting the user's receipt address caused an unknown exception"); } } }
configuration file
#Spring reads the data in the configuration file: ${user.address.max-count} user.address.max-count=20
3. Test if the business tier functionality is working.
@SpringBootTest @RunWith(SpringRunner.class) public class AddressServiceTest { @Autowired IAddressService addressService; @Test public void addNewAddress() { Address address = new Address(); address.setPhone("11111111111"); address.setName("Zhang Zhang"); addressService.addNewAddress(50,"Li Si",address); } }
5. New Receipt Address-Controller
5.1 Handling Exceptions
The business layer throws an exception that the total number of corresponding receipt addresses exceeds the standard and needs to be handled in the baseController
else if (e instanceof AddressCountLimitException) { result.setState(4003); result.setMessage("Exception for number of receipt addresses exceeding limit for user"); }
5.2 Design Request
/addresses/add_new_address post Address address,Httpsession session JsonResult<Void>
5.3 Processing Requests
Create AddressCountroller in the Control Layer to process requests and responses for user receipt addresses
package com.jiabowen.store.controller; import com.jiabowen.store.entity.Address; import com.jiabowen.store.service.IAddressService; import com.jiabowen.store.util.JsonResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RequestMapping("address") @RestController public class AddressController extends BaseController { @Autowired private IAddressService addressService; @RequestMapping("add_new_address") public JsonResult<Void> addNewAddress(Address address, HttpSession session){ Integer uid = getUidFromSession(session); String username = getUsernameFormSession(session); addressService.addNewAddress(uid,username,address); return new JsonResult<>(OK); } }
Test interface:
-
Log on first
-
Visit after landing: http://localhost:8080/address/add_new_address?name=tom&phone=11222333444
6 New Receipt Address-Front Interface
<script> //1. Listen for the registration button to be clicked, if clicked you can execute a method $("#btn-add-new-address").click(function () { //2. Send ajax $.ajax({ url: "/address/add_new_address", type: "POST", data: $("#form-add-new-address").serialize(), dataType: "JSON", success: function (json) { if (json.state == 200){ alert("New Receipt Address Succeeded") console.log(json) }else{ alert("Failed to add new receipt address") } }, error: function (xhr) { alert("Unknown error when adding new receipt address" + xhr.status) } }); }); </script>
7 Get a list of provinces and municipalities
1. Get a list of provinces and municipalities
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;
The parent attribute represents the code number of the parent region, and the parent code number of the province is + 86
2. Get a list of provinces and municipalities - entity classes
public class District extends BaseEntity { private Integer id; private String parent; private String code; private String name; }
3. Get a list of provinces and municipalities - Permanent Layer
Query statement:
select * from t_dict_district where parent = ? order by code ASC
asc: ascending order
Abstract method definition: DistrictMapper interface
package com.jiabowen.store.mapper; import com.jiabowen.store.entity.District; import java.util.List; public interface DistrictMapper { /** * Query region information based on parent code */ List<District> findByParent(Integer parent); }
Interface Mapping
<?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.jiabowen.store.mapper.DistrictMapper"> <select id="DistrictMapper" resultType="com.jiabowen.store.entity.District"> select * from t_dict_district where parent = #{parent} order by code ASC </select> </mapper>
Test persistence layer
@Test public void findByParent(){ List<District> list = districtMapper.findByParent("210100"); System.err.println(666666); for (District district : list) { System.out.println(district); } }
4. Get a list of provinces and municipalities - business layer
1. Create an interface IDistrictService and define an abstract method
public interface IDistrictService { /** * Query region information based on parent code (provincial and urban) * @param parent Parent Code * @return Multiple Area Information */ List<District> getByParent(String parent); }
2. Create DistrictServiceImpl implementation class to implement abstract methods
@Service public class DistrictService implements IDistrictService { @Autowired private DistrictMapper districtMapper; @Override public List<District> getByParent(String parent) { List<District> list = districtMapper.findByParent(parent); /** * When transferring network data, null can be set for invalid data in order to avoid the transfer of invalid data as much as possible. * Save traffic and increase efficiency */ for (District district : list) { district.setId(null); district.setParent(null); } return list; } }
3. Conduct unit testing
@SpringBootTest @RunWith(SpringRunner.class) public class DistrictServiceTest { @Autowired private IDistrictService districtService; @Test public void getByParent(){ List<District> list = districtService.getByParent("210100"); for (District district : list) { System.out.println(district); } } }
5 Get List of Provincial and Urban Areas - Control Layer
5.1 Design Request
/districts GET String parent JsonResult<List<District>>
5.2 Implementation Request
Create a DistrictController class in which you write methods to handle requests.
@RequestMapping("districts") @RestController public class DistrictController extends BaseController { @Autowired private IDistrictService districtService; @RequestMapping({"/",""}) public JsonResult<List<District>> getByParent(String parent){ List<District> data = districtService.getByParent(parent); return new JsonResult<>(OK, data); } }
Add the districts request to the whitelist.
patterns.add("/districts/**");
Direct request server, access: localhost:8080/districts?parent=86
6 Get a list of provinces and municipalities - front-end page
1. Comment out the JS code used to load the provincial and urban lists through js.
<!-- <script type="text/javascript" src="../js/distpicker.data.js"></script> <script type="text/javascript" src="../js/distpicker.js"></script> -->
2. Check if the front-end page has a related name attribute when submitting provincial and urban data
3. Run the front end to see if you can save data (in addition to provincial and urban areas).
Get the name of the province or city
1 Get the name of the province or city
1. The plan obtains the name of the current province or city according to the current code, which corresponds to a query statement
select * from t_dist_districts where code = ?
2. Define in the DistrictMapper interface
String findNameByCode(String code);
3. In DistrictMapper. Add a mapping of an abstract method to the XML file.
<select id="findNameByCode" resultType="java.lang.String"> select name from t_dict_district where code = #{code} </select>
4. Unit test methods
@Test public void findNameByCode(){ String name = districtMapper.findNameByCode("210000"); System.out.println(name); }
2 Get the name of the province or city - the business layer
1. There are no exceptions to handle at the business level
2. Define abstract methods in corresponding business-tier interfaces
String getNameByCode(String code);
3. Implement in subclasses
@Override public String getNameByCode(String code) { String nameByCode = districtMapper.findNameByCode(code); return nameByCode; }
4. Testing
Note: More than 8 lines of code should be tested independently
3Obtaining the name of a province or an urban area-Business layer optimization
1. Adding an address layer depends on the IDistrictService layer
//The business layer that adds a user's receipt address relies on the business interface of IDistrictService @Autowired private IDistrictService districtService;
2. In the addNewAddress method, the provincial and urban data obtained from the districtService interface is transferred to the address object, which contains all the data of the user's harvest address.
String provinceNameByCode = districtService.getNameByCode(address.getProvinceCode()); String cityNameByCode = districtService.getNameByCode(address.getCityCode()); String areaNameByCode = districtService.getNameByCode(address.getAreaCode()); address.setProvinceName(provinceNameByCode); address.setCityName(cityNameByCode); address.setAreaName(areaNameByCode);
@Service public class AddressServiceImpl implements IAddressService { @Autowired private AddressMapper addressMapper; //The business layer that adds a user's receipt address relies on the business interface of IDistrictService @Autowired private IDistrictService districtService; @Value("${user.address.max-count}") private Integer maxCount; @Override public void addNewAddress(Integer uid, String username, Address address) { //Call the method of harvesting address statistics Integer count = addressMapper.countByUid(uid); if (count >= maxCount){ throw new AddressCountLimitException("User receipt address exceeds maximum"); } String provinceNameByCode = districtService.getNameByCode(address.getProvinceCode()); String cityNameByCode = districtService.getNameByCode(address.getCityCode()); String areaNameByCode = districtService.getNameByCode(address.getAreaCode()); address.setProvinceName(provinceNameByCode); address.setCityName(cityNameByCode); address.setAreaName(areaNameByCode); //Set uid isdefault address.setUid(uid); Integer isdefault = count == 0 ? 1 : 0;//1 means default, 0 means not default address.setIsDefault(isdefault); //Complete Log address.setCreatedUser(username); address.setModifiedUser(username); address.setCreatedTime(new Date()); address.setModifiedTime(new Date()); //Method of inserting receipt address Integer rows = addressMapper.insert(address); if (rows != 1){ throw new InsertException("Inserting the user's receipt address caused an unknown exception"); } } }
4 Get the provincial-urban-front interface
1.addAddress. Write the corresponding provincial and urban display on the HTML page and restrict the content in the corresponding label according to the user's different choices.
2. Write relevant event code
<script> //The value attribute represents the code value of the current region let defaultOption = "<option value = '0'>---Please select---</option>" $(document).ready(function () { showProvinceList(); //Set the default Please Select value as the default value for the control $("#city-list").append(defaultOption); $("#area-list").append(defaultOption); $("#province-list").append(defaultOption); }); $("#city-list").change(function () { //Get Administrative Region Parent Code First let parent = $("#city-list").val(); //Empty all option elements in the select drop-down list $("#area-list").empty(); //Fill in the default value "Please Select" $("#area-list").append(defaultOption); if (parent == 0){ return; } $.ajax({ url: "/districts", type: "GET", data: "parent=" + parent, dataType: "JSON", success: function (json) { if (json.state == 200){ let list = json.data; for (let i = 0; i < list.length; i++) { let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>" $("#area-list").append(opt); } }else{ alert("County Information Loading Failed") } } }); }); /* * change()Function that monitors whether a control has changed and triggers a parameter whenever it has changed * A function(){} needs to be passed * */ $("#province-list").change(function () { //Get Administrative Region Parent Code First let parent = $("#province-list").val(); //Empty all option elements in the select drop-down list $("#city-list").empty(); $("#area-list").empty(); //Fill in the default value "Please Select" $("#city-list").append(defaultOption); $("#area-list").append(defaultOption); if (parent == 0){ return; } $.ajax({ url: "/districts", type: "GET", data: "parent=" + parent, dataType: "JSON", success: function (json) { if (json.state == 200){ let list = json.data; for (let i = 0; i < list.length; i++) { let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>" $("#city-list").append(opt); } }else{ alert("City Information Loading Failed") } } }); }); /** * Provincial drop-down list data display */ function showProvinceList(){ $.ajax({ url: "/districts", type: "POST", data: "parent=86", dataType: "JSON", success: function (json) { if (json.state == 200){ let list = json.data; for (let i = 0; i < list.length; i++) { let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>" $("#province-list").append(opt); } }else{ alert("province/Municipality Information Loading Failed") } } }); } //1. Listen for the registration button to be clicked, if clicked you can execute a method $("#btn-add-new-address").click(function () { //2. Send ajax $.ajax({ url: "/address/add_new_address", type: "POST", data: $("#form-add-new-address").serialize(), dataType: "JSON", success: function (json) { if (json.state == 200){ alert("New Receipt Address Succeeded") console.log(json) }else{ alert("Failed to add new receipt address") } }, error: function (xhr) { alert("Unknown error when adding new receipt address" + xhr.status) } }); }); </script>