Implementing CRUD Operations with Spring Boot, MyBatis-Plus, and JSP Views

Controller for Managing Receiving Addresses

package com.example.web.controller;

import com.example.core.entity.DeliveryAddress;
import com.example.core.service.DeliveryAddressService;
import com.example.core.util.ServiceResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.time.LocalDateTime;

@Controller
@RequestMapping("/deliveryAddress")
public class DeliveryAddressController {
    @Autowired
    private DeliveryAddressService addressService;

    @GetMapping("/{id}")
    public ModelAndView findAddressById(@PathVariable("id") Integer id) {
        ServiceResponse response = addressService.findAddressById(id);
        ModelAndView mv = new ModelAndView();
        mv.addObject("response", response);
        mv.setViewName("deliveryAddress/detail");
        return mv;
    }

    @GetMapping
    public ModelAndView findAllForCustomer() {
        Integer customerId = 1;
        ServiceResponse response = addressService.findAllByCustomerId(customerId);
        ModelAndView mv = new ModelAndView();
        mv.addObject("response", response);
        mv.setViewName("deliveryAddress/list");
        return mv;
    }

    @PostMapping
    public ModelAndView createAddress(DeliveryAddress address) {
        address.setCustomerId(1);
        ServiceResponse response = addressService.createAddress(address);
        ModelAndView mv = new ModelAndView();
        if (response.getStatusCode() == 200) {
            mv.setViewName("redirect:/deliveryAddress");
        } else {
            mv.addObject("response", response);
            mv.setViewName("/deliveryAddress/create");
        }
        return mv;
    }

    @DeleteMapping("/{id}")
    public ModelAndView deactivateAddress(@PathVariable("id") Integer addressId) {
        ServiceResponse response = addressService.deactivateAddress(addressId);
        ModelAndView mv = new ModelAndView();
        if (response.getStatusCode() == 200) {
            mv.setViewName("redirect:/deliveryAddress");
        } else {
            mv.setViewName("deliveryAddress/list");
            mv.addObject("deactivationError", "Deletion failed");
        }
        return mv;
    }

    @GetMapping("/edit/{id}")
    public ModelAndView getForEdit(@PathVariable("id") Integer id) {
        ServiceResponse response = addressService.findAddressById(id);
        ModelAndView mv = new ModelAndView();
        mv.addObject("response", response);
        mv.setViewName("deliveryAddress/edit");
        return mv;
    }

    @PutMapping
    public ModelAndView modifyAddress(DeliveryAddress address) {
        address.setModificationTime(LocalDateTime.now());
        ServiceResponse response = addressService.modifyAddress(address);
        ModelAndView mv = new ModelAndView();
        if (response.getStatusCode() == 200) {
            mv.setViewName("redirect:/deliveryAddress/" + address.getId());
        } else {
            mv.addObject("modificationError", "Update failed");
            mv.setViewName("edit");
        }
        return mv;
    }
}

Entity Class

package com.example.core.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;

@TableName("delivery_address")
public class DeliveryAddress implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "address_id", type = IdType.AUTO)
    private Integer id;
    private Long recipientPhone;
    private String recipientName;
    private Integer customerId;
    private String province;
    private String city;
    private String district;
    private String street;
    private String detail;
    private Integer status;
    private Integer version;
    private LocalDateTime creationTime;
    private LocalDateTime modificationTime;

    // Getters and Setters omitted for brevity
}

Mapper Interface

package com.example.core.repository;

import com.example.core.entity.DeliveryAddress;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface DeliveryAddressMapper extends BaseMapper<DeliveryAddress> {
}

Service Implementation

package com.example.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.core.entity.DeliveryAddress;
import com.example.core.repository.DeliveryAddressMapper;
import com.example.core.service.DeliveryAddressService;
import com.example.core.util.ServiceResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class DeliveryAddressServiceImpl implements DeliveryAddressService {
    @Autowired
    private DeliveryAddressMapper addressRepository;

    @Override
    public ServiceResponse findAddressById(Integer id) {
        DeliveryAddress address = addressRepository.selectById(id);
        return address != null ? ServiceResponse.success(address) : ServiceResponse.failure("Address not found");
    }

    @Override
    public ServiceResponse findAllByCustomerId(Integer customerId) {
        LambdaQueryWrapper<DeliveryAddress> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeliveryAddress::getCustomerId, customerId)
               .eq(DeliveryAddress::getStatus, 1);
        List<DeliveryAddress> addresses = addressRepository.selectList(wrapper);
        if (addresses == null || addresses.isEmpty()) {
            return ServiceResponse.failure("No delivery addresses found");
        }
        return ServiceResponse.success(addresses);
    }

    @Override
    public ServiceResponse createAddress(DeliveryAddress address) {
        address.setStatus(1);
        address.setVersion(1);
        address.setCreationTime(LocalDateTime.now());
        int affectedRows = addressRepository.insert(address);
        return affectedRows > 0 ? ServiceResponse.success(address) : ServiceResponse.failure("Creation failed");
    }

    @Override
    public ServiceResponse deactivateAddress(Integer id) {
        DeliveryAddress address = addressRepository.selectById(id);
        address.setStatus(0);
        address.setVersion(address.getVersion() + 1);
        int affectedRows = addressRepository.updateById(address);
        return affectedRows > 0 ? ServiceResponse.success(address) : ServiceResponse.failure("Deactivation failed");
    }

    @Override
    public ServiceResponse modifyAddress(DeliveryAddress address) {
        int currentVersion = addressRepository.selectById(address.getId()).getVersion();
        address.setVersion(currentVersion + 1);
        int affectedRows = addressRepository.updateById(address);
        return affectedRows > 0 ? ServiceResponse.success(address) : ServiceResponse.failure("Modification failed");
    }
}

Service Interface

package com.example.core.service;

import com.example.core.entity.DeliveryAddress;
import com.example.core.util.ServiceResponse;

public interface DeliveryAddressService {
    ServiceResponse findAddressById(Integer id);
    ServiceResponse findAllByCustomerId(Integer customerId);
    ServiceResponse createAddress(DeliveryAddress address);
    ServiceResponse deactivateAddress(Integer id);
    ServiceResponse modifyAddress(DeliveryAddress address);
}

Response Utility Class

package com.example.core.util;

public class ServiceResponse {
    private int statusCode;
    private String message;
    private Object payload;

    public static ServiceResponse success(Object payload) {
        return new ServiceResponse(200, "Operation succeeded", payload);
    }

    public static ServiceResponse failure(Object payload) {
        return new ServiceResponse(400, "Operation failed", payload);
    }

    public static ServiceResponse successWithMessage(String message, Object payload) {
        return new ServiceResponse(200, message, payload);
    }

    // Constructor and Getters/Setters omitted for brevity
}

Database Schema

CREATE TABLE `delivery_address` (
  `address_id` int NOT NULL AUTO_INCREMENT,
  `recipient_phone` bigint DEFAULT NULL,
  `recipient_name` varchar(255) DEFAULT NULL,
  `customer_id` int DEFAULT NULL,
  `province` varchar(255) NOT NULL,
  `city` varchar(255) NOT NULL,
  `district` varchar(255) NOT NULL,
  `street` varchar(255) NOT NULL,
  `detail` varchar(255) NOT NULL,
  `status` int DEFAULT NULL,
  `version` int DEFAULT NULL,
  `creation_time` datetime DEFAULT NULL,
  `modification_time` datetime DEFAULT NULL,
  PRIMARY KEY (`address_id`),
  KEY `fk_address_customer` (`customer_id`),
  CONSTRAINT `fk_address_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`)
);

Application Configuration

server:
  servlet:
    context-path: /api
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/app_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: db_user
    password: db_password
  mvc:
    view:
      prefix: /
      suffix: .jsp
    hiddenmethod:
      filter:
        enabled: true

JSP View Examples

Detail Page (detail.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Address Details</title>
</head>
<body>
Recipient: ${response.payload.recipientName} <br>
Phone: ${response.payload.recipientPhone}<br>
Address: ${response.payload.province} ${response.payload.city} ${response.payload.district} ${response.payload.street} ${response.payload.detail}
</body>
</html>

List Page (list.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Address List</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.7.0.min.js"></script>
    <style>
        /* CSS styles for address list */
    </style>
</head>
<body>
${deactivationError}
<c:choose>
    <c:when test="${response.statusCode != 200}">
        No data available
    </c:when>
    <c:otherwise>
        <div class="container">
            <h2>My Delivery Addresses</h2>
            <ul class="addressList" id="addressList">
                <c:forEach var="addr" items="${response.payload}">
                    <li>
                        <div class="btn-container">
                            <a href="${pageContext.request.contextPath}/deliveryAddress/edit/${addr.id}">Edit</a>
                            <form method="post" action="${pageContext.request.contextPath}/deliveryAddress/${addr.id}">
                                <input type="hidden" name="_method" value="DELETE">
                                <input type="button" value="Remove" class="removeBtn">
                            </form>
                        </div>
                        <h3>${addr.recipientName}</h3>
                        <p>Phone: ${addr.recipientPhone}</p>
                        <p>Address: ${addr.province} ${addr.city} ${addr.district} ${addr.street} ${addr.detail}</p>
                    </li>
                </c:forEach>
            </ul>
        </div>
    </c:otherwise>
</c:choose>
<script>
    document.querySelector(".addressList").onclick = function(event) {
        var targetElement = event.target;
        if (targetElement.nodeName === 'INPUT' && targetElement.className === 'removeBtn') {
            if (confirm("Confirm removal of this address?")) {
                targetElement.parentElement.submit();
            }
        }
    };
</script>
</body>
</html>

Create Form (create.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Add Delivery Address</title>
    <style>
        /* Form styling */
    </style>
</head>
<body>
<div class="container">
    <h2>Add New Address</h2>
    <form id="addressForm" method="post" action="${pageContext.request.contextPath}/deliveryAddress">
        <label for="recipient">Recipient Name:</label>
        <input type="text" id="recipient" name="recipientName" required>
        <label for="phone">Phone Number:</label>
        <input type="tel" id="phone" name="recipientPhone" required>
        <label for="provinceSelect">Province:</label>
        <select id="provinceSelect" name="province" required>
            <option value="">Select Province</option>
            <option value="Jiangsu">Jiangsu</option>
            <option value="Zhejiang">Zhejiang</option>
            <option value="Guangdong">Guangdong</option>
        </select>
        <label for="citySelect">City:</label>
        <select id="citySelect" name="city" required>
            <option value="">Select City</option>
        </select>
        <label for="districtInput">District:</label>
        <input type="text" id="districtInput" name="district" required>
        <label for="streetInput">Street:</label>
        <input type="text" id="streetInput" name="street" required>
        <label for="detailInput">Detail:</label>
        <input type="text" id="detailInput" name="detail" required>
        <input type="submit" value="Submit">
    </form>
</div>
<script>
    const cityMapping = {
        "Jiangsu": ["Suzhou", "Nanjing", "Wuxi"],
        "Zhejiang": ["Hangzhou", "Ningbo", "Wenzhou"],
        "Guangdong": ["Guangzhou", "Shenzhen", "Dongguan"]
    };
    document.getElementById("provinceSelect").addEventListener("change", function() {
        const citySelect = document.getElementById("citySelect");
        citySelect.innerHTML = '<option value="">Select City</option>';
        const selectedCities = cityMapping[this.value];
        if (selectedCities) {
            selectedCities.forEach(city => {
                const option = document.createElement("option");
                option.value = city;
                option.textContent = city;
                citySelect.appendChild(option);
            });
        }
    });
</script>
</body>
</html>

Edit Form (edit.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Edit Address</title>
    <style>
        /* Form styling */
    </style>
</head>
<body>
<div class="container">
    <h2>Edit Address</h2>
    <form action="${pageContext.request.contextPath}/deliveryAddress" method="post">
        <input type="hidden" name="_method" value="PUT"/>
        <input type="hidden" name="id" value="${response.payload.id}">
        <label for="recipientEdit">Recipient Name:</label>
        <input type="text" id="recipientEdit" name="recipientName" value="${response.payload.recipientName}" required>
        <label for="phoneEdit">Phone:</label>
        <input type="tel" id="phoneEdit" name="recipientPhone" value="${response.payload.recipientPhone}" required>
        <label for="provinceEdit">Province:</label>
        <select id="provinceEdit" name="province" required>
            <option value="${response.payload.province}">${response.payload.province}</option>
            <option value="Jiangsu">Jiangsu</option>
            <option value="Zhejiang">Zhejiang</option>
            <option value="Guangdong">Guangdong</option>
        </select>
        <label for="cityEdit">City:</label>
        <select id="cityEdit" name="city" required>
            <option value="${response.payload.city}">${response.payload.city}</option>
        </select>
        <label for="districtEdit">District:</label>
        <input type="text" id="districtEdit" name="district" value="${response.payload.district}" required>
        <label for="streetEdit">Street:</label>
        <input type="text" id="streetEdit" name="street" value="${response.payload.street}" required>
        <label for="detailEdit">Detail:</label>
        <input type="text" id="detailEdit" name="detail" value="${response.payload.detail}" required>
        <input type="submit" value="Update">
    </form>
</div>
<script>
    // Same city mapping and population logic as create.jsp
</script>
</body>
</html>

Tags: Spring Boot mybatis-plus CRUD JSP ModelAndView

Posted on Sat, 26 Sep 2026 16:16:38 +0000 by stefandv