Leyou Mall (15) -- order service

Keywords: Java Spring Boot

Leyou Mall (15) – order service

1, Order settlement page

Page Jump

At the bottom of the shopping cart page, there is a button to settle:

When you click settlement, you should jump to the order settlement page, that is, getOrderInfo.html

To view the settlement button of the shopping cart:

As you can see, the address is correct. However, only the logged in user can settle the payment, so you can't jump directly. Instead, verify the user's login status before jumping. If you find that you are not logged in, you should redirect to the login page!

Bind the click event to this button:

Judge the login status in the event and jump to the page:

toOrderInfo() {
    // Determine whether to log in
    ly.verifyUser().then(() => {
        // Logged in
        window.location.href = "/getOrderInfo.html"
    }).catch(() => {
        // Not logged in
        window.location.href = "/login.html?returnUrl=" + window.location.href;
    })
}

Post login test:

The content to be rendered on this page mainly includes three parts:

  • Consignee information
  • Payment method
  • Commodity information

2, Address management

2.1 page effect

Click "add receiving address" and "Edit" to pop up the modal box, as shown below:

2.2 database design

CREATE TABLE `tb_address`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'address id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT 'user id',
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Consignee Name ',
  `phone` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Consignee telephone',
  `zip_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Zip code',
  `state` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'province',
  `city` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'city',
  `district` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'area/county',
  `address` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Detailed address',
  `default_address` tinyint(1) NULL DEFAULT NULL COMMENT '1: Default address 0: non default address',
  `label` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Address label',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `userId`(`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2.3 page rendering

2.3.1 define data model

2.3.2 form modification

<div tabindex="-1" role="dialog" data-hasfoot="false" class="sui-modal hide fade edit">
   <div class="modal-dialog">
      <div class="modal-content">
         <div class="modal-header">
            <button type="button" @click="clear" data-dismiss="modal" aria-hidden="true" class="sui-close">×</button>
            <h4 id="myModalLabel" class="modal-title">{{isEdit ? "edit" : "add to"}}Receiving address</h4>
         </div>
         <div class="modal-body">
            <form id="myform" action="" class="sui-form form-horizontal">
               <div class="control-group">
                  <label class="control-label">consignee:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.name" class="input-medium">
                  </div>
               </div>
               <div class="control-group">
                  <label class="control-label">contact number:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.phone" class="input-medium">
                  </div>
               </div>
               <div class="control-group">
                  <label class="control-label">Province:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.state" class="input-medium">
                  </div>
               </div>
               <div class="control-group">
                  <label class="control-label">City:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.city" class="input-medium">
                  </div>
               </div>
               <div class="control-group">
                  <label class="control-label">area/County:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.district" class="input-medium">
                  </div>
               </div>

               <div class="control-group">
                  <label class="control-label">Zip code:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.zipCode" class="input-medium">
                  </div>
               </div>

               <div class="control-group">
                  <label class="control-label">Detailed address:</label>
                  <div class="controls">
                     <input type="text" v-model="addressForm.address" class="input-large">
                  </div>
               </div>
               <div class="control-group">
                  <label class="control-label">Address label:</label>
                  <div class="controls">
                     <select class="select" v-model="addressForm.label">
                        <option value="home">home</option>
                        <option value="company">company</option>
                        <option value="school">school</option>
                     </select>
                  </div>
               </div>
               <div class="control-group">
                  <div  style="margin-left: 100px">
                     <input type="checkbox" v-model="addressForm.defaultAddress" class="checkbox">Set as default shipping address
                  </div>
               </div>

            </form>
         </div>
         <div class="modal-footer">
            <button type="button" @click="addressSave" data-ok="modal" class="sui-btn btn-primary btn-large">determine</button>
            <button type="button" @click="clear" data-dismiss="modal" class="sui-btn btn-default btn-large">cancel</button>
         </div>
      </div>
   </div>
</div>

2.3.3 method binding

New address

Modify address

Submit and cancel forms

There are two places to cancel, one is cancel and the other is X

2.4 back end implementation

2.4.1 entity class

@Table(name = "tb_address")
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @NotNull
    private Long userId;        //User id
    private String name;        //Consignee name
    private String phone;       //Receiving mobile phone
    private String zipCode;     //Zip code
    private String state;       //province
    private String city;        //city
    private String district;    //District / county
    private String address;     //Specific address
    private Boolean defaultAddress; //Is it the default address
    private String label;       //label
    //get and set
}

2.4.2,AddressMapper

/**
 * Address Generic mapper for
 */
public interface AddressMapper extends Mapper<Address> {
}

2.4.3,AddressController

Basic addition, deletion, modification and query

@RestController
@Api("Address management interface")
@RequestMapping("/address")
public class AddressController {

    @Autowired
    private AddressService addressService;

    /**
     * Add receiving address
     * @param address
     * @return
     */
    @PostMapping
    @ApiOperation(value = "Add a receiving address of the user",notes = "Create shipping address")
    @ApiImplicitParam(name = "address",required = true,value = "Receiving address object")
    @ApiResponses({
            @ApiResponse(code = 201,message = "Address added successfully"),
            @ApiResponse(code = 500,message = "Server exception")
    })
    public ResponseEntity<Void> addAddress(@RequestBody Address address){
        this.addressService.addAddress(address);
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }

    /**
     * Query all receiving addresses according to user id
     * @return
     */
    @GetMapping
    @ApiOperation(value = "Query all receiving addresses under the current login user",notes = "Query receiving address")
    @ApiResponses({
            @ApiResponse(code = 200,message = "All receiving addresses of the user were queried successfully"),
            @ApiResponse(code = 404,message = "The receiving address of the user is not found"),
            @ApiResponse(code = 500,message = "Server exception")
    })
    public ResponseEntity<List<Address>> queryAddressByUserId(){
        List<Address> addresses = this.addressService.queryAddressByUserId();
        if (CollectionUtils.isEmpty(addresses)){
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(addresses);
    }

    /**
     * Update shipping address based on user id
     * @param address
     * @return
     */
    @PutMapping
    @ApiOperation(value = "Update the receiving address of the current user",notes = "Update shipping address")
    @ApiImplicitParam(name = "address",required = true,value = "Receiving address object")
    @ApiResponses({
            @ApiResponse(code = 204,message = "Update of receiving address succeeded"),
            @ApiResponse(code = 500,message = "Server exception")
    })
    public ResponseEntity<Void> updateAddressByUserId(@RequestBody Address address){
        this.addressService.updateAddress(address);
        return ResponseEntity.noContent().build();
    }

    /**
     * Query the receiving address according to the address id
     * @param addressId
     * @return
     */
    @GetMapping("{addressId}")
    @ApiOperation(value = "Query a receiving address",notes = "Query receiving address")
    @ApiImplicitParam(name = "addressId",value = "Receiving address No",required = true)
    @ApiResponses({
            @ApiResponse(code = 200,message = "query was successful"),
            @ApiResponse(code = 404,message = "Address not found"),
            @ApiResponse(code = 500,message = "Server exception")

    })
    public ResponseEntity<Address> queryAddressById(@PathVariable("addressId") Long addressId){
        Address address = this.addressService.queryAddressById(addressId);
        if (null == address){
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(address);
    }

    /**
     * Delete a shipping address
     * @param addressId
     * @return
     */
    @DeleteMapping("{addressId}")
    @ApiOperation(value = "Delete a shipping address",notes = "Delete shipping address")
    @ApiImplicitParam(name = "addressId",value = "Receiving address No",required = true)
    @ApiResponses({
            @ApiResponse(code = 200,message = "Delete succeeded"),
            @ApiResponse(code = 500,message = "Deletion failed")
    })
    public ResponseEntity<Void> deleteAddress(@PathVariable("addressId") Long addressId){
        this.addressService.deleteAddress(addressId);
        return ResponseEntity.ok().build();
    }
}

2.4.4,AddressService

public interface AddressService {
    /**
     * Add receiving address
     * @param address
     * @return
     */
    void addAddress(Address address);

    /**
     * Query all receiving addresses according to user id
     * @return
     */
    List<Address> queryAddressByUserId();

    /**
     * Update shipping address based on user id
     * @param address
     * @return
     */
    void updateAddress(Address address);

    /**
     * Query the receiving address according to the address id
     * @param addressId
     * @return
     */
    Address queryAddressById(Long addressId);

    /**
     * Delete a shipping address
     * @param addressId
     * @return
     */
    void deleteAddress(Long addressId);
}

Implementation class:

@Service
public class AddressServiceImpl implements AddressService {

    @Autowired
    private AddressMapper addressMapper;

    /**
     * Add receiving address
     *
     * @param address
     * @return
     */
    @Override
    public void addAddress(Address address) {
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        address.setUserId(userInfo.getId());
        setDefaultAddress(address);
        this.addressMapper.insert(address);
    }

    /**
     * Query all receiving addresses according to user id
     *
     * @return
     */
    @Override
    public List<Address> queryAddressByUserId() {
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        Example example = new Example(Address.class);
        example.createCriteria().andEqualTo("userId",userInfo.getId());
        return this.addressMapper.selectByExample(example);
    }

    /**
     * Update shipping address based on user id
     *
     * @param address
     * @return
     */
    @Override
    public void updateAddress(Address address) {
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        address.setUserId(userInfo.getId());
        setDefaultAddress(address);
        this.addressMapper.updateByPrimaryKeySelective(address);
    }

    /**
     * Query the receiving address according to the address id
     *
     * @param addressId
     * @return
     */
    @Override
    public Address queryAddressById(Long addressId) {
        //You also need to match the user id when querying
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        Example example = new Example(Address.class);
        example.createCriteria().andEqualTo("id",addressId).andEqualTo("userId",userInfo.getId());
        return this.addressMapper.selectByExample(example).get(0);
    }

    /**
     * Delete a shipping address
     *
     * @param addressId
     * @return
     */
    @Override
    public void deleteAddress(Long addressId) {
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        Example example = new Example(Address.class);
        example.createCriteria().andEqualTo("id",addressId).andEqualTo("userId",userInfo.getId());
        this.addressMapper.deleteByExample(example);
    }

    /**
     * Set the default state of the previous address to false
     * @param address
     */
    private void setDefaultAddress(Address address){
        if (address.getDefaultAddress()){
            List<Address> addresses = queryAddressByUserId();
            //If this address is set as the default address, other addresses under this user should be non default addresses
            addresses.forEach(addr ->{
                if (addr.getDefaultAddress()){
                    addr.setDefaultAddress(false);
                    this.addressMapper.updateByPrimaryKeySelective(addr);
                }
            });
        }
    }
}

2.4.5 Gateway Routing

2.5 interface test

cookie information needs to be set during interface test

2.5.1. New address

Data entry:

{     
   "name":"Li Si",  
   "phone":"13555555555", 
   "zipCode":"123123", 
   "state":"Sichuan Province",   
   "city":"Chengdu",  
   "district":"High tech Zone", 
   "address":"Chengdu hi tech Zone, Sichuan Province", 
   "label":"company", 
   "defaultAddress":true
}

result

View database:

2.5.2. Query all addresses

result

Currently, the user has only one address

2.5.3 address modification

Data entry:

{     
   "id":"4",
   "name":"Li Si modified",  
   "phone":"13555555555", 
   "zipCode":"123123", 
   "state":"Sichuan Province",   
   "city":"Chengdu",  
   "district":"High tech Zone", 
   "address":"Chengdu hi tech Zone, Sichuan Province", 
   "label":"Company modification", 
   "defaultAddress":true
}

result

Database:

2.5.4. Query an address

result

2.5.5 delete an address

result

Query the address of the current user through the query all addresses interface:

2.6 page transformation

2.6.1 address query

When the page is loaded, query all address information under the current login user. Then save it in the optional address list addresses for rendering. When querying the address, put the default address first:

Page rendering

effect

Default address:

A user can only set one default address, so it needs to be handled when adding and modifying addresses. If the new or modified address is set as the default address, other addresses of the user will become non default addresses

2.6.2 add address

addressSave(){
   //1. Verify whether to log in
   ly.verifyUser().then(() => {
      //2. Log in, make a request, save or modify the address
      if (this.isEdit === false) {
         //2.1 NEW
         ly.http.post("/address", this.addressForm).then(() => {
            //Save successfully, reload data
            this.loadData();
            //Empty form
            this.clear();
         }).catch()
      }else {
         //2.2 modification
         ly.http.put("/address", this.addressForm).then(() => {
            //Modification succeeded. Reload the data
            this.loadData();
            //Empty form
            this.clear();
         }).catch()
      }
   }).catch(() => {
      //3. Not logged in
      window.location.href = "/login.html?returnUrl=" + window.location.href;
   });
}

Here, add and modify requests are combined, and a data model is used to mark whether to modify or add:

2.6.3 data echo

When you click Modify, query the corresponding address information through the passed in address id, and then echo it to the form

editAddress(id){
   this.isEdit = true;
   ly.verifyUser().then(() => {
      ly.http.get("/address/"+id).then(({data}) => {
         this.addressForm = data;
      })
   }).catch(() => {
      window.location = "/login.html?returnUrl=" + window.location.href;
   })
}

2.6.4 address deletion

deleteAddress(id){
   ly.verifyUser().then(() => {
      ly.http.delete("/address/"+id).then(() => {
         this.loadData();
      })
   }).catch(() => {
      window.location.href = "/login.html?returnUrl=" + window.location.href;
   });
}

3, Payment method

There are two payment methods:

  • Wechat payment
  • Cash on Delivery

Associated with paymentType in order data:

Therefore, a data model is defined in the Vue instance to record the payment method:

It is then associated with this variable when the page is rendered:

4, Commodity information

design sketch

The delivery list here is actually the goods to be paid selected by the user in the shopping cart

Therefore, it is necessary to carry the information of the selected shopping cart while the shopping cart jumps over

4.1. Shopping cart information acquisition

Modify the page Jump logic in cart.html to transfer the shopping cart information selected by the user:

Then obtain the shopping cart data in the created hook function and save it to the local attribute. Note that the user login status should be verified before obtaining the data. If it is found that the user is not logged in, it will be redirected to the login page directly:

Then reload the page to view the console:

4.2 page rendering

4.3 total amount

It can be seen that there are four main data:

  • Total amount: totalPay
  • Discount cash back: discount
  • Freight: postFee
  • Paid in amount: actualPay

However, there is no preferential activity module at present. In addition, the freight needs to be calculated in combination with the logistics system. For the time being, it is not available and set to 0. Write it in the order attribute:

totalPay and actualPay values are obtained by calculating attributes:

computed:{
   totalNum(){
      return this.carts.reduce((c1,c2) => c1 + c2.num,0);
   },
   totalPay(){
      return this.carts.reduce((c1,c2) => c1 + c2.price * c2.num,0);
   },
   actualPay(){
      return this.totalPay + this.order.postFee - this.order.discount;
   }
}

Then render on the page:

There is also a display of the receiving address, which is rendered together

4.4. Submit order

4.4.1 page submission

See the data required for the order interface:

{
  "totalPay": 236800,
  "postFee": 0,
  "paymentType": 2,
  "actualPay": 236800,
  "buyerMessage": null,
  "buyerNick": "huge",
  "orderDetails": [
    {
      "skuId": 3893493,
      "num": 1,
      "title": "Apples( Apple)iPhone 6 (A1586) 16GB Golden Mobile Unicom Telecom 4 G Mobile 3",
      "price": 236800,
      "ownSpec": "{\"body color \":\"Diamond carving blue\",\"Memory\":\"4GB\",\"Fuselage storage\":\"64GB\"}",
      "image": "http://image.leyou.com/images/9/4/1524297342728.jpg"
    }
  ],
  "receiver": "Account cancellation",
  "receiverMobile": "15800000000",
  "receiverState": "Shanghai",
  "receiverCity": "Shanghai",
  "receiverDistrict": "Pudong New Signature",
  "receiverAddress": "Building 3, dump truck, No. 18, hangtou Road, hangtou town",
  "receiverZip": "210000",
  "invoiceType": 0,
  "sourceType":2
}

It is divided into three parts

  • Basic information of the order itself

    • Total amount
    • Paid in amount
    • Payment type
    • Buyer information is the current user
  • Order details

    • It is the goods in the shopping cart, but the shopping cart data will have an additional userId, which can be removed:

  • Logistics information

    • Logistics address information selected by the current user

Binding event:

Note: @ click.prevent is used to prevent the default jump of a tag and execute the submit function.

method

methods: {
    submit() {
        // Process shopping cart data into order details
        const orderDetails = this.carts.map(({userId, ...rest}) => rest);
        // Processing logistics information
        const addr = this.addresses[this.selectedAddress];
        const obj = {
            receiver: addr.name,
            receiverState: addr.state,
            receiverCity: addr.city,
            receiverAddress: addr.address,
            receiverDistrict: addr.district,
            receiverMobile: addr.phone,
            receiverZip: addr.zipCode
        };
        // Copy to order object
        Object.assign(this.order, obj, {
            orderDetails,
            totalPay: this.totalPay,
            actualPay: this.actualPay,
        });
        // place order
        ly.http.post("/order", this.order).then(({data}) => {
            // Online payment, need to go to the payment page
            window.location = "pay.html?orderId=" + data;
        }).catch((resp) => {
            alert("Order submission failed. Please try again later!")
        })
    }
},

4.4.2 accuracy loss

Click submit test on the page:

Order id in database:

But look carefully at the order id carried on the page:

As mentioned earlier, there will be precision loss. What is the reason?

This is actually because JS's Long integer precision is limited, and java's Long type data is out of range, so there is a precision loss.

JSON's string is returned in the background. JSON.parse() method will be automatically called inside axios to convert JSON string into JS data, and progress loss will occur. If you do not convert and still use it as a string, there will be no problem.

Of course, this is only one of the solutions. The front-end solution is not elegant enough

Back end solution:

Jackson is used by default in Spring MVC. Solved by rewriting the converter

@Configuration
@EnableWebMvc //You need to use swagger to test, and you need to annotate this annotation temporarily
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter =
                new MappingJackson2HttpMessageConverter();

        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
        converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
    }
}

5, Wechat payment

5.1 introduction

Official wechat payment documents: https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F

Select the document center and click API document

Select Native payment in basic payment and click development guide

5.2 development process

Business Process Description:

  1. The merchant background system generates orders according to the commodities purchased by users.
  2. Users confirm payment and call WeChat payment (unified order API) to generate pre paid transactions.
  3. After receiving the request, the wechat payment system generates an advance payment transaction form and returns the QR code link code of the transaction session_ url.
  4. The merchant background system returns the code according to the_ The URL generates a QR code.
  5. The user opens the wechat "scan" to scan the QR code, and the wechat client sends the scanned content to the wechat payment system.
  6. The wechat payment system receives the client request and initiates user payment after verifying the validity of the link, requiring user authorization.
  7. After the user enters the password in the wechat client and confirms the payment, the wechat client submits the authorization.
  8. The wechat payment system completes the payment transaction according to the user's authorization.
  9. After completing the payment transaction, the wechat payment system returns the transaction results to the wechat client, and prompts the user of the transaction results through SMS and wechat messages. Wechat client displays the payment transaction result page.
  10. The wechat payment system notifies the merchant background system of the payment results by sending asynchronous messages. The merchant background system needs to reply to the reception and notify the wechat background system not to send the payment notice of this order.
  11. If the payment notice is not received, the merchant background system calls [query order API].
  12. The merchant will deliver the goods to the user after confirming that the order has been paid.

concrete work

Here is a summary of what the merchant should do:

  • Merchant generates order

  • The merchant calls the wechat order interface to obtain the link of pre transaction

  • The merchant will link to generate a QR code picture and display it to the user;

  • User pays and confirms

  • Payment result notice:

    • Wechat asynchronously informs the merchant of the payment results, and the merchant informs the wechat payment reception
    • If the merchant does not receive the notification, it can call the interface to query the payment status
  • If the payment is successful, the order will be shipped and the order status will be modified

In the previous business, we have completed:

  • Generate order

What needs to be done next is:

  • Call wechat interface to generate links.

  • Generate payment QR code picture

5.3. Generate QR code

5.3.1. Generate pre transaction link

First call the background service according to the order number to generate a transaction link, and then generate a QR code according to the link

Initiate a request on the page:

var payVm = new Vue({
        el:"#payVm",
        data:{
            ly,
            orderId:0, //Order id
        },
        components:{
            shortcut: () => import("/js/pages/shortcut.js")
        },
        created(){
            this.loadData();
        },
        methods:{
            loadData(){
                //1. Judge whether the user logs in
                ly.verifyUser().then(() => {
                    //2. Get order number
                    this.orderId = ly.getUrlParam("orderId");
                    //3. Get request link
                    ly.http.get("/order/url/" + this.orderId).then(resp => {
                        console.log(resp.data);
                        new QRCode(document.getElementById("qrImage"),{
                            text:resp.data,
                            width:250,
                            height:250,
                            colorDark: "#000000",
                            colorLight: "#ffffff",
                            correctLevel: QRCode.CorrectLevel.H
                        });
                    });
                }).catch(() => {
                    //4. If you are not logged in, go to the login page
                    location.href = "/login.html?returnUrl=" + location.href;
                })
            }
        }
    });

Note: app.js should be introduced last, because the div with id app must be available before Vue can get the corresponding element

The interface for generating payment address has been defined in the background: generateUrl

5.3.2. Generate QR code

Use the JS plug-in generating QR Code: qrcode, official website: https://github.com/davidshimjs/qrcodejs

Bring the js into the project

Page introduction

The page defines a div to display the QR code

QR code related styles

5.4. Payment status query

However, because it is not clear when the user will pay, a circular method is adopted here to constantly request to judge whether the payment is successful

Payment successful

6, Page optimization

6.1. The payment page displays the total amount

getOrderInfo.html

When the order is successfully submitted and the order number is returned, the calculated total amount is stored in LocalStorage as the page jumps to the payment page, and then displayed where necessary

pay.html

When loading data, get the total amount:

Page rendering:

paysuccess.html

When loading the payment success page, first authenticate the user, then read the total amount and delete the local storage

Page rendering:

6.2. Modify the transfer method of order number

Put the order number into the local storage and no longer pass it through the access path.

Payment is successful. Delete the order number in LocalStorage.

If payment fails, you can also jump to the payment page to continue the payment operation

Modify order submission function

Get the order number from the payment page

After the payment is successful, delete the locally stored order number

6.3. Shopping cart data update

After successful payment, delete the data stored locally (paysuccess.html)

After the user pays successfully, the paid goods will be deleted from the shopping cart.

New interface: query skuId by order id

controller

  • Request method: GET
  • Request path: / order/skuId/{id}
  • Request parameter: id, order id
  • Return result: item number collection
/**
 * Query all skuids under the order according to the order id
 * @param orderId
 * @return
 */
@GetMapping("/skuId/{id}")
@ApiOperation(value = "Query all commodity numbers under the order according to the order number",notes = "Query commodity number")
@ApiImplicitParam(name = "id",value = "Order No",type = "Long")
@ApiResponses({
        @ApiResponse(code = 200,message = "Item order number collection"),
        @ApiResponse(code = 404,message = "The item under this order number was not found"),
        @ApiResponse(code = 500,message = "Server exception")
})
public ResponseEntity<List<Long>> querySkuIdByOrderId(@PathVariable("id") Long orderId){
    List<Long> skuIds = this.orderService.querySkuIdByOrderId(orderId);
    if (CollectionUtils.isEmpty(skuIds)){
        return ResponseEntity.notFound().build();
    }
    return ResponseEntity.ok(skuIds);
}

Service

/**
 * Query all skuids under the order according to the order id
 * @param orderId
 * @return
 */
List<Long> querySkuIdByOrderId(Long orderId);

Implementation class:

/**
 * Query all skuids under the order according to the order id
 *
 * @param orderId
 * @return
 */
@Override
public List<Long> querySkuIdByOrderId(Long orderId) {
    Example example = new Example(OrderDetail.class);
    example.createCriteria().andEqualTo(orderId);
    List<OrderDetail> orderDetails = this.orderDetailMapper.selectByExample(example);
    //Return item collection
    List<Long> skuIds = new ArrayList<>();
    orderDetails.forEach(orderDetail -> skuIds.add(orderDetail.getSkuId()));
    return skuIds;
}

Front end page processing

Posted by akluch on Sun, 05 Sep 2021 18:17:30 -0700