SpringBoot integrates JPA to implement paging and CRUD

SpringBoot integrates JPA to implement paging and CRUD

Article directory

  • SpringBoot integrates JPA to implement paging and CRUD
    • pom.xml
    • application.properties
    • addCategory.jsp
    • editCategory.jsp
    • hello.jsp
    • listCategory.jsp
    • Category
    • CategoryDAO
    • CategoryService
    • CategoryServiceImpl
    • Page4Navigator
    • RedisConfig
    • CategoryController
    • HelloController







Too lazy to type the code, just copy:
SpringBoot integrates JPA to implement paging and CRUD

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.moon</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot</name>
    <description>springboot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

        <!--To add this using jsp-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <!--Database-->
        <!-- mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <!-- jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

Fill in your own database and password

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update

###########################redis###################### ###
#Redis database index (default is 0)
spring.redis.database=0
#Redis server address
spring.redis.host=127.0.0.1
#Redis server connection port
spring.redis.port=6379
#Redis server connection password (default is empty)
spring.redis.password=
#Maximum number of connections in the connection pool (use negative values to indicate no limit)
spring.redis.pool.max-active=10
#The maximum blocking waiting time of the connection pool (use a negative value to indicate no limit)
spring.redis.pool.max-wait=-1
#Maximum idle connection in the connection pool
spring.redis.pool.max-idle=8
#Minimum idle connection in the connection pool
spring.redis.pool.min-idle=0
#Connection timeout (milliseconds)
spring.redis.timeout=0

spring.jpa.show-sql=true

addCategory.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<div style="margin: 0px auto; width: 500px">
    <form action="updateCategory" method="post">
        name:<input name="name" value="${category.name}"><br>
        <button type="submit">Submit</button>
    </form>
</div>

editCategory.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false"%>

<div style="margin: 0px auto; width: 500px">
    <form action="updateCategory" method="post">
        name:<input name="name" value="${c.name}"><br>
        <input name="id" type="hidden" value="${c.id}">
        <button type="submit">Submit</button>
    </form>
</div>

hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false"%>

<div style="margin: 0px auto; width: 500px">
    <form action="updateCategory" method="post">
        name:<input name="name" value="${c.name}"><br>
        <input name="id" type="hidden" value="${c.id}">
        <button type="submit">Submit</button>
    </form>
</div>

listCategory.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div align="center"></div>
<div style="width: 500px;margin: 20px auto;text-align: center">
    <table align="center" border="1" cellspacing="0">
        <caption>Employees<a href="addCategory">Add</a></caption>
        <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>Edit</th>
            <th>Delete</th>
        </tr>
        </thead>
        <tbody>
        <c:forEach items="${page.content}" var="c" varStatus="st">
            <tr>
                <td>${<!-- -->c.id}</td>
                <td>${<!-- -->c.name}</td>
                <td><a href="editCategory?id=${c.id}">Edit</a></td>
                <td><a href="deleteCategory?id=${c.id}">Delete</a></td>
            </tr>
        </c:forEach>
        </tbody>
    </table>
    <div>
        <a href="?start=0">【Home】</a>
        <a href="?start=${page.number-1}">【Previous page】</a>
        <a href="?start=${page.number + 1}">[Next page]</a>
        <a href="?start=${page.totalPages-1}">[Last page]</a>
    </div>
    <div>

    </div>
</div>

Category

package com.moon.springboot.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

/**
 * @Author moon
 * @Date 2023/9/26 21:05
 * @Description
 */
@Entity
@Table(name = "category_")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Category {<!-- -->
    @Id
    //Indicate the self-increasing method
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    privateInteger id;

    @Column(name = "name")
    private String name;
}

CategoryDAO

package com.moon.springboot.dao;

import com.moon.springboot.pojo.Category;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @Author moon
 * @Date 2023/9/26 21:18
 * @Description
 * Generic <Category, Integer> indicates that this is a DAO for the Category class, and Integer indicates that the primary key is of Integer type.
 * JpaRepository, the parent interface, provides a series of queries such as CRUD, paging, etc.
 */
public interface CategoryDAO extends JpaRepository<Category, Integer> {<!-- -->
}

CategoryService

package com.moon.springboot.service;

import com.moon.springboot.pojo.Category;
import com.moon.springboot.util.Page4Navigator;
import org.springframework.data.domain.Pageable;

public interface CategoryService {<!-- -->

    public Page4Navigator<Category> list(Pageable pageable);

    public void save(Category category);

    public void delete(int id);

    public Category get(int id);
}

CategoryServiceImpl

package com.moon.springboot.service.impl;

import com.moon.springboot.dao.CategoryDAO;
import com.moon.springboot.pojo.Category;
import com.moon.springboot.service.CategoryService;
import com.moon.springboot.util.Page4Navigator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;



@Service
@CacheConfig(cacheNames="category")
public class CategoryServiceImpl implements CategoryService {<!-- -->

    @Autowired
    CategoryDAO categoryDAO;

    @Override
    @Cacheable(key="'category ' + #p0.offset + '-' + #p0.pageSize ")
    public Page4Navigator<Category> list(Pageable pageable) {<!-- -->
        Page<Category> pageFromJPA= categoryDAO.findAll(pageable);
        Page4Navigator<Category> page = new Page4Navigator<>(pageFromJPA,5);
        return page;
    }

    @Override
    @Cacheable(key="'category ' + #p0")
    public Category get(int id) {<!-- -->
        Category c =categoryDAO.getOne(id);
        return c;
    }

    @Override
    @CacheEvict(allEntries=true)
// @CachePut(key="'category ' + #p0")
    public void save(Category category) {<!-- -->
        // TODO Auto-generated method stub
        categoryDAO.save(category);
    }

    @Override
    @CacheEvict(allEntries=true)
// @CacheEvict(key="'category ' + #p0")
    public void delete(int id) {<!-- -->
        // TODO Auto-generated method stub
        categoryDAO.deleteById(id);
    }

}

Page4Navigator

When executing the query method, you can pass in a PageRequest object to represent paging query.
The PageRequest object represents the conditions and constraints of the query, usually including the current page number and several pieces of data per page.
You can also specify Direction or Sort when performing paging queries.

The result of the query is a Page object, which contains all data-related information on the current page.
Common methods of Page object:
getTotalPages() How many pages are there in total?
getTotalElements() How many pieces of data are there in total?
getNumber() gets the current page number
getSize() specifies how many elements there are on each page
getNumberOfElements() How many elements are actually on the current page?
hasContent() Whether the current page has data
getContent() gets all the data in the current page (List)
getSort() gets the paging query sorting rules
isFirst() Whether the current page is the first page
isLast() Whether the current page is the last page
hasPrevious() whether there is a previous page
hasNext() whether there is a next page

package com.moon.springboot.util;

import java.util.List;

import org.springframework.data.domain.Page;

public class Page4Navigator<T> {<!-- -->
    Page<T> page4jpa;
    //Number of pages for navigation paging
    int navigatePages;

    //Total number of pages to print
    int totalPages;

    int number;

    long totalElements;

    int size;

    int numberOfElements;

    List<T> content;

    boolean isHasContent;

    boolean first;

    boolean last;

    boolean isHasNext;

    boolean isHasPrevious;

    int[] navigatepageNums;

    public Page4Navigator() {<!-- -->
        //This empty paging is specially provided for Redis to convert from json format to Page4Navigator object.
    }

    public Page4Navigator(Page<T> page4jpa,int navigatePages) {<!-- -->
        this.page4jpa = page4jpa;
        this.navigatePages = navigatePages;

        totalPages = page4jpa.getTotalPages();

        number = page4jpa.getNumber();

        totalElements = page4jpa.getTotalElements();

        size = page4jpa.getSize();

        numberOfElements = page4jpa.getNumberOfElements();

        content = page4jpa.getContent();

        isHasContent = page4jpa.hasContent();

        first = page4jpa.isFirst();

        last = page4jpa.isLast();

        isHasNext = page4jpa.hasNext();

        isHasPrevious = page4jpa.hasPrevious();

        calcNavigatepageNums();

    }

    private void calcNavigatepageNums() {<!-- -->
        int navigatepageNums[];
        int totalPages = getTotalPages();
        int num = getNumber();
        //When the total number of pages is less than or equal to the number of navigation pages
        if (totalPages <= navigatePages) {<!-- -->
            navigatepageNums = new int[totalPages];
            for (int i = 0; i < totalPages; i + + ) {<!-- -->
                navigatepageNums[i] = i + 1;
            }
        } else {<!-- --> //When the total number of pages is greater than the number of navigation pages
            navigatepageNums = new int[navigatePages];
            int startNum = num - navigatePages / 2;
            int endNum = num + navigatePages / 2;

            if (startNum < 1) {<!-- -->
                startNum = 1;
                //(The first navigationPages page
                for (int i = 0; i < navigatePages; i + + ) {<!-- -->
                    navigatepageNums[i] = startNum + + ;
                }
            } else if (endNum > totalPages) {<!-- -->
                endNum = totalPages;
                //Last navigatePages page
                for (int i = navigatePages - 1; i >= 0; i--) {<!-- -->
                    navigatepageNums[i] = endNum--;
                }
            } else {<!-- -->
                //All intermediate pages
                for (int i = 0; i < navigatePages; i + + ) {<!-- -->
                    navigatepageNums[i] = startNum + + ;
                }
            }
        }
        this.navigatepageNums = navigatepageNums;
    }

    public int getNavigatePages() {<!-- -->
        return navigatePages;
    }

    public void setNavigatePages(int navigatePages) {<!-- -->
        this.navigatePages = navigatePages;
    }

    public int getTotalPages() {<!-- -->
        return totalPages;
    }

    public void setTotalPages(int totalPages) {<!-- -->
        this.totalPages = totalPages;
    }

    public int getNumber() {<!-- -->
        return number;
    }

    public void setNumber(int number) {<!-- -->
        this.number = number;
    }

    public long getTotalElements() {<!-- -->
        return totalElements;
    }

    public void setTotalElements(long totalElements) {<!-- -->
        this.totalElements = totalElements;
    }

    public int getSize() {<!-- -->
        return size;
    }

    public void setSize(int size) {<!-- -->
        this.size = size;
    }

    public int getNumberOfElements() {<!-- -->
        return numberOfElements;
    }

    public void setNumberOfElements(int numberOfElements) {<!-- -->
        this.numberOfElements = numberOfElements;
    }

    public List<T> getContent() {<!-- -->
        return content;
    }

    public void setContent(List<T> content) {<!-- -->
        this.content = content;
    }

    public boolean isHasContent() {<!-- -->
        return isHasContent;
    }

    public void setHasContent(boolean isHasContent) {<!-- -->
        this.isHasContent = isHasContent;
    }

    public boolean isFirst() {<!-- -->
        return first;
    }

    public void setFirst(boolean first) {<!-- -->
        this.first = first;
    }

    public boolean isLast() {<!-- -->
        return last;
    }

    public void setLast(boolean last) {<!-- -->
        this.last = last;
    }

    public boolean isHasNext() {<!-- -->
        return isHasNext;
    }

    public void setHasNext(boolean isHasNext) {<!-- -->
        this.isHasNext = isHasNext;
    }

    public boolean isHasPrevious() {<!-- -->
        return isHasPrevious;
    }

    public void setHasPrevious(boolean isHasPrevious) {<!-- -->
        this.isHasPrevious = isHasPrevious;
    }

    public int[] getNavigatepageNums() {<!-- -->
        return navigatepageNums;
    }

    public void setNavigatepageNums(int[] navigatepageNums) {<!-- -->
        this.navigatepageNums = navigatepageNums;
    }

}

RedisConfig

package com.moon.springboot.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {<!-- -->

    private RedisSerializer<String> keySerializer() {<!-- -->

        return new StringRedisSerializer();
    }

    private RedisSerializer<Object> valueSerializer() {<!-- -->
        return new GenericJackson2JsonRedisSerializer();//value value uses json serializer
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {<!-- -->

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();

        redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L))//Set the cache delay time to 30 minutes
                .disableCachingNullValues()//If it is a null value, do not cache it
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//Set key value serialization
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));//Set the value value to be serialized into json
        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory))
                .cacheDefaults(redisCacheConfiguration).build();

    }
}

CategoryController

package com.moon.springboot.web;

import com.moon.springboot.pojo.Category;
import com.moon.springboot.service.CategoryService;
import com.moon.springboot.util.Page4Navigator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class CategoryController {<!-- -->
    @Autowired
    CategoryService categoryService;

    @RequestMapping("/listCategory")
    public String listCategory(Model m,@RequestParam(value = "start", defaultValue = "0") int start,@RequestParam(value = "size", defaultValue = "5") int size ) throws Exception {<!-- -->
        start = start<0?0:start;
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(start, size, sort);
        Page4Navigator<Category> page =categoryService.list(pageable);
        m.addAttribute("page", page);
        return "listCategory";
    }

    @RequestMapping("/addCategory")
    public String addCategory(Category c) throws Exception {<!-- -->
        categoryService.save(c);
        return "redirect:listCategory";
    }
    @RequestMapping("/deleteCategory")
    public String deleteCategory(Category c) throws Exception {<!-- -->
        categoryService.delete(c.getId());
        return "redirect:listCategory";
    }
    @RequestMapping("/updateCategory")
    public String updateCategory(Category c) throws Exception {<!-- -->
        categoryService.save(c);
        return "redirect:listCategory";
    }
    @RequestMapping("/editCategory")
    public String editCategory(int id,Model m) throws Exception {<!-- -->
        Category c= categoryService.get(id);
        m.addAttribute("c", c);
        return "editCategory";
    }
}

HelloController

package com.moon.springboot.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.DateFormat;
import java.util.Date;

/**
 * @Author moon
 * @Date 2023/9/25 21:17
 * @Description
 */

@Controller
public class HelloController {<!-- -->

    @RequestMapping("/hello")
    public String hello(Model model) {<!-- -->
        model.addAttribute("now", DateFormat.getDateTimeInstance().format(new Date()));
        return "hello";
    }

    @RequestMapping("/hello_1")
    public String hello_1(Model model) {<!-- -->
        model.addAttribute("now", DateFormat.getDateTimeInstance().format(new Date()));
        return "hello_1";
    }
}