Web应用技术(第十六周/END)

news2024/11/26 1:53:09

本次练习基于how2j的教程完成对SpringBoot的初步学习。

初识Springboot

  • 学习导入:
  • 1.第一个基于SpringBoot的项目:
    • (1)application.java:
      • 该文件中的核心代码:
    • (2)HelloController.java:
      • 该文件的核心部分——两个注解:
        • @RestController:
        • @RequestMapping:
    • (3)pom.xml:
    • (4)运行效果:
    • (5)运行流程:
    • (6)Vue的路由和Web应用程序的路由:
  • 2.SpringBoot部署——war包方式:
  • 3.基于SpringBoot的CRUD(注解方式):
    • (1)实现思路:
    • (2)具体实现:
      • 添加按钮:
      • 完善DAO:
      • 完善控制器(含分页插件“PageHelper”详解):
      • 运行查看:
  • 4.SpringBoot+MyBatis(配置文件方式):
  • 5.解决“Whitelabel Error Page”问题:

学习导入:

在学习SpringBoot前,我们已经学习过SSM了,即Spring、SpringMVC、MyBatis,SpringBoot是与Spring对标的,那么我们可以在学习之前向自己提两个问题:

  • 什么是SpringBoot?
  • 它和Spring有什么区别和联系(为什么要学SpringBoot)?

Spring Boot是一个用于创建基于Spring框架的快速应用程序的开源Java开发框架。它提供了开箱即用的配置,使得开发者可以更加专注于应用程序的业务逻辑而不是繁琐的配置工作。它的核心思想是约定优于配置,即根据一些默认约定来自动配置应用程序,从而简化了开发流程。

Spring Boot是Spring框架的扩展和增强,它建立在Spring框架之上并提供了许多方便的功能。以下是Spring Boot和Spring的区别和联系:

区别:

  • 编码风格不同:Spring Boot鼓励使用Java Config而非XML配置来构建应用程序,并且提供了一些简化的注解用于快速创建Bean,从而使得开发流程更加高效。

  • 自动化配置不同:Spring框架需要手动配置大量的组件来启动应用程序,例如Servlet容器、数据库连接等。而Spring Boot则采用约定优于配置的方式,自动配置这些组件,从而减少了繁琐的配置工作。

  • 依赖管理不同:Spring Boot提供了一个基于Maven或Gradle的依赖管理工具,可以方便地添加所需的各种依赖库,并自动处理版本冲突问题。

联系:

  • 共享Spring核心功能:Spring Boot建立在Spring框架的核心组件之上,包括IoC容器、AOP、数据访问、Web、测试等。因此,Spring Boot应用程序可以像普通的Spring应用程序一样使用这些核心组件。

  • Spring Boot应用程序可以使用Spring框架的所有扩展:Spring Boot应用程序可以使用Spring框架中的所有扩展,例如Spring Security、Spring Data等。

下面是一个简单的示例代码,演示了如何在Spring Boot中创建一个Web应用程序,并使用Spring框架中的IoC容器来管理Bean:

@RestController // 声明这是一个RESTful API控制器
@SpringBootApplication // 标记这是一个Spring Boot应用程序
public class MyApplication {

    @Autowired
    private MyService myService; // 使用@Autowired注解自动装配MyService Bean

    @GetMapping("/") // 处理HTTP GET请求的路由
    public String home() {
        return "Hello, " + myService.getMessage(); // 返回"Hello, World!"
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args); // 启动Spring Boot应用程序
    }
}

@Service // 标记这是一个Spring管理的Bean
public class MyService {

    public String getMessage() {
        return "World!"; // 返回字符串"World!"
    }
}

在上面的代码中,@RestController和@GetMapping注解是Spring Boot的特有标记,用于创建RESTful API。而@Autowired和@Service注解则是Spring框架的核心组件,用于IoC容器的依赖注入和Bean的创建。可以看到,Spring Boot和Spring框架是密切相关的,共同构建了现代Java应用程序的基础。

1.第一个基于SpringBoot的项目:

how2j上的项目建设和部署流程很清楚,我不赘述了,下面我提供带有注释的代码,并且附上一些我的个人理解。

(1)application.java:

package com.how2java.springboot;

import org.springframework.boot.SpringApplication; //导入SpringApplication类
import org.springframework.boot.autoconfigure.SpringBootApplication; //导入SpringBootApplication类
import org.springframework.boot.builder.SpringApplicationBuilder; //导入SpringApplicationBuilder类
import org.springframework.boot.web.servlet.ServletComponentScan; //导入ServletComponentScan类
import org.springframework.boot.web.support.SpringBootServletInitializer; //导入SpringBootServletInitializer类

@SpringBootApplication //声明该类为Spring Boot应用程序的入口
@ServletComponentScan //扫描带有@WebServlet、@WebFilter、@WebListener注解的组件
public class Application extends SpringBootServletInitializer { //继承SpringBootServletInitializer类,以支持war包形式的部署

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { //重写configure方法,以支持war包形式的部署
		return application.sources(Application.class); //返回SpringApplicationBuilder对象
	}

	public static void main(String[] args) { //应用程序的入口
		SpringApplication.run(Application.class, args); //启动Spring Boot应用程序
	}
}

该文件中的核心代码:

SpringApplication.run(Application.class, args); //启动Spring Boot应用程序

SpringApplication.run(Application.class, args)是用于启动Spring Boot应用程序的方法,其具体解析如下:

  • SpringApplication是Spring Boot中的一个静态类,提供了各种启动和配置Spring Boot应用程序的方法。

  • run()方法是启动Spring Boot应用程序的入口点。它需要两个参数:主要配置类的Class对象和main方法的args数组。

  • Application.class是主要配置类的Class对象。在Spring Boot应用程序中,我们需要创建一个Java类作为主要配置类,并在其中定义应用程序的配置信息、数据源等组件。在这里,我们将Application类作为主要配置类的Class对象传递给run()方法。

  • args是main方法接收到的命令行参数。通常情况下,我们不需要传递任何参数给run()方法,直接传递空数组即可。

当调用SpringApplication.run(Application.class, args)方法时,Spring Boot会执行以下步骤:

  1. 加载主要配置类,并创建Spring IoC容器。

  2. 自动扫描并注册所有的Bean组件。

  3. 根据配置信息自动装配Bean组件之间的依赖关系。

  4. 启动内嵌的Web服务器(例如Tomcat或Jetty)。

  5. 监听HTTP请求,并将请求分发到相应的控制器进行处理。

(2)HelloController.java:

// 定义了Java包名,即该类所在的包。
package com.how2java.springboot.web;

// 导入了org.springframework.web.bind.annotation.RequestMapping类,用于处理HTTP请求的注解。
// 导入了org.springframework.web.bind.annotation.RestController类,用于声明该类为RESTful风格的控制器。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// 使用@RestController注解标记该类为RESTful控制器。
@RestController
public class HelloController {

    // 使用@RequestMapping注解标记该方法为处理HTTP请求的方法,其中"/hello"表示请求的URL路径。
    @RequestMapping("/hello")
    // 定义了该方法的具体实现,即返回一个字符串"Hello Spring Boot!"。
    public String hello() {
        return "Springboot测试!";
    }

}

该文件的核心部分——两个注解:

@RestController:

@RestController是一个Spring MVC注解,它用于声明一个类为RESTful风格的控制器。在Spring Boot应用程序中,我们通常使用@RestController来定义RESTful Web服务。

具体来说,@RestController注解告诉Spring MVC框架,该类是一个控制器,并且该控制器的每个方法都会返回一个HTTP响应,而不是一个视图。这意味着,当我们使用@RestController注解标记一个控制器类时,Spring MVC框架会自动将该类的方法返回的数据转换成相应的HTTP响应,并将其发送给客户端。

@RequestMapping:

@RequestMapping是SpringMVC的注解,相信大家已经很熟悉了,简单来说,它的功能就是为当前的控制器打一个标记,以便浏览器通过Tomcat 根据HTTP请求的URL,顺利地找到这个控制器。

(3)pom.xml:

<!-- 定义了Maven项目的POM文件 -->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- 定义了Maven模型的版本号 -->
    <modelVersion>4.0.0</modelVersion>

  <!-- 定义了项目的groupId -->
  <groupId>com.how2java</groupId>
  <!-- 定义了项目的artifactId -->
  <artifactId>springboot</artifactId>
  <!-- 定义了项目的版本号 -->
  <version>0.0.1-SNAPSHOT</version>
  <!-- 定义了项目的名称 -->
  <name>springboot</name>
 	<packaging>war</packaging>
  <!-- 定义了项目的描述 -->
 
  <description>springboot</description>
  
    <!-- 定义了项目的父级依赖,即使用了Spring Boot的starter parent,版本为1.5.9.RELEASE。 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <!-- 定义了项目的依赖,包括spring-boot-starter-web和junit,其中junit的scope为test,表示只在测试时使用。 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>           
        </dependency>
        
	    <dependency>
		      <groupId>junit</groupId>
		      <artifactId>junit</artifactId>
		      <version>3.8.1</version>
		      <scope>test</scope>
	    </dependency>
    </dependencies>

    <!-- 定义了项目的属性,包括Java版本为1.8。 -->
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <!-- 定义了项目的构建配置,包括使用Spring Boot的Maven插件进行构建。 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这个文件定义了Maven工程项目的配置信息及项目的相关依赖。

(4)运行效果:

运行Application.java,访问地址:http://127.0.0.1:8080/hello

在这里插入图片描述

(5)运行流程:

当我们运行第一个文件时,实际上启动了一个SpringBoot应用程序。SpringBoot应用程序会启动一个内嵌的Tomcat服务器并开始监听HTTP请求,将请求分发到相应的控制器进行处理。

在第二个文件中,我们定义了一个RESTful控制器,它包含一个处理HTTP请求的方法,即hello()方法。当我们访问http://127.0.0.1:8080/hello时,Tomcat服务器会将请求路由到该控制器的hello()方法中,并返回该方法的返回值,即Springboot测试!字符串。因此,我们可以在浏览器中看到该字符串的内容。

(6)Vue的路由和Web应用程序的路由:

由于最近打算用Vue来做课设,在Vue的学习过程中也见到了这个名词

Vue.js官方文档中,路由(Router)被定义为管理应用程序中视图之间导航的机制。Vue
Router是Vue.js官方提供的路由管理器,允许我们通过URL路径来定义应用程序的不同视图,并且可以通过路由参数来传递数据。

举个例子,如果我们正在开发一个电子商务网站,我们可能需要在不同的页面中展示不同的商品列表。我们可以使用Vue Router来实现这个功能。首先,我们需要在Vue应用程序中安装Vue Router,并在Vue实例中声明路由器:

import Vue from 'vue'
import VueRouter from 'vue-router'
import ProductList from './components/ProductList.vue'
import ProductDetails from './components/ProductDetails.vue'

Vue.use(VueRouter)

const routes = [
  { path: '/', component: ProductList },
  { path: '/product/:id', component: ProductDetails, props: true }
]

const router = new VueRouter({
  routes
})

在这个例子中,我们定义了两个路由:一个是根路径(‘/’),对应于商品列表页面,另一个是’/product/:id’,对应于商品详情页面。我们还通过props选项将路由参数传递给ProductDetails组件。

然后,在Vue实例中,我们需要将路由器添加到Vue实例中:

new Vue({
  router,
  el: '#app'
})

最后,在模板中,我们可以使用router-link组件来生成链接到不同的路由:

<router-link to="/">Product List</router-link>
<router-link :to="{ name: 'product', params: { id: 1 }}">Product Details</router-link>

在这个例子中,我们使用router-link组件生成两个链接:一个链接到根路径(‘/’),另一个链接到商品详情页面。通过使用路由器和router-link组件,我们可以轻松地实现在Vue应用程序中进行页面导航的功能。


而在Web应用程序中,路由是指将HTTP请求映射到相应的处理程序或控制器的过程。当客户端发送HTTP请求时,服务器会根据请求的URL路径和其他参数选择相应的处理程序或控制器来处理请求,并返回相应的响应。这个过程就是路由。

在Spring Boot应用程序中,路由是通过Spring MVC框架来实现的。当我们定义一个控制器类,并在其中定义一个处理HTTP请求的方法时,我们可以使用Spring MVC的注解来将该方法映射到一个特定的URL路径。例如,在第二个文件中,我们使用了@RequestMapping("/hello")注解将hello()方法映射到/hello路径。当客户端发送一个HTTP GET请求到/hello路径时,Spring MVC框架会自动将该请求路由到hello()方法,并执行该方法的代码。该方法可以返回任何类型的数据,例如字符串、JSON对象等,Spring MVC框架会将该数据转换成相应的HTTP响应,并将其发送给客户端。

2.SpringBoot部署——war包方式:

Tomcat 是一款常用的 Java Web 应用服务器,而 WAR 包是一种 Java Web 应用程序的标准部署格式。通过将 Spring Boot + Maven 项目打包成 WAR 包后,可以方便地将应用程序部署到 Tomcat 或其他支持 WAR 包格式的Web 服务器上,从而实现对应用程序的发布和运行。

在课堂上我成功打包并且运行了,那个时候项目比较简单,只有hello相关程序和配置,现在我尝试打包具备CRUD的整个项目时总是失败,访问时显示

在这里插入图片描述

后面再试试来debug吧。

3.基于SpringBoot的CRUD(注解方式):

理解了前面SSM的CRUD,SpringBoot的CRUD易如反掌!!
SSM的CRUD还没有搞懂的可以看这篇博客Web应用技术(第十五周/END)。


(1)实现思路:

实现SpringBoot的CRUD的思想与SSMCRUD的思想是一样的:
我们的crud本质上,也是一种向用户提供的服务,或者说用户的需求。因此为了实现CRUD:

  • 我们需要修改视图,增加相关按钮,以供用户点击

  • 我们需要修改定义服务的接口,以实现接口最终实现功能

  • 我们需要修改DAO(CategoryMapper),以实现与数据库的交互。

  • 我们需要修改控制器,处理用户不同的/更多的请求。

我们这里由于是通过开源的插件来实现分页的因此还必须额外在pom.xml中添加相关依赖,如果是手动分页就没有这个必要了。

由于我们这是一个小型的项目,不需要进行规范化也不需要进行分工合作,因此我们可以不去写接口来强行定义(规范化)我们的程序需要实现哪些服务,这里how2j从简而行了,没有写接口,其实我认为SSM那里的CRUD也是没有必要去先写一个接口的。

(2)具体实现:

具体细节见Web应用技术(第十五周/END),这里只提供代码和注释,不做重复讲解了。

添加按钮:

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"> <!-- HTML页面布局 -->

</div>
 
<div style="width:500px;margin:20px auto;text-align: center"> <!-- HTML页面布局 -->
    <table align='center' border='1' cellspacing='0'> <!-- HTML表格 -->
        <tr> <!-- 表头 -->
            <td>id</td>
            <td>name</td>
            <td>编辑</td>
            <td>删除</td>
        </tr>
        <c:forEach items="${page.list}" var="c" varStatus="st"> <!-- 使用JSTL的forEach标签循环遍历查询结果,并将结果设置到HTML页面中 -->
            <tr>
                <td>${c.id}</td> <!-- 输出Category对象的id属性 -->
                <td>${c.name}</td> <!-- 输出Category对象的name属性 -->
                <td><a href="editCategory?id=${c.id}">编辑</a></td> <!-- 创建超链接,用于跳转到编辑页面 -->
                <td><a href="deleteCategory?id=${c.id}">删除</a></td> <!-- 创建超链接,用于提交删除请求 -->
            </tr>
        </c:forEach>
         
    </table>
    <br>
    <div>
                <a href="?start=1">[首  页]</a> <!-- 创建分页导航,用于快速跳转到指定页面 -->
            <a href="?start=${page.pageNum-1}">[上一页]</a>
            <a href="?start=${page.pageNum+1}">[下一页]</a>
            <a href="?start=${page.pages}">[末  页]</a>
    </div>
    <br>
    <form action="addCategory" method="post"> <!-- 创建表单,用于提交新增请求 -->
    id:<input name="id"> <br> <!-- 创建输入框,用于输入新增记录的名称属性 -->
     
    name: <input name="name"> <br> <!-- 创建输入框,用于输入新增记录的名称属性 -->
    <button type="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"> <!-- HTML页面布局 -->

<form action="updateCategory" method="post"> <!-- 创建表单,用于提交更新请求 -->

name: <input name="name" value="${c.name}"> <br> <!-- 创建输入框,用于输入更新记录的名称属性,并设置初始值为原有值,通过EL表达式获取 -->

<input name="id" type="hidden" value="${c.id}"> <!-- 创建隐藏域,用于提交更新记录的id属性,通过EL表达式获取 -->
<button type="submit">提交</button> <!-- 创建提交按钮,用于提交更新请求 -->

</form>
</div>


完善DAO:

package com.how2java.springboot.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.how2java.springboot.pojo.Category;

@Mapper // 声明该接口为MyBatis的Mapper接口,需要通过@MapperScan注解扫描到该类
public interface CategoryMapper {

    @Select("select * from category_ ") // 使用@Select注解指定SQL查询语句
    List<Category> findAll(); // 定义findAll()方法,用于查询所有Category对象,并以List集合的形式返回结果集

    @Insert(" insert into category_ ( id,name ) values (#{id},#{name}) ") // 使用@Insert注解指定SQL插入语句
    public int save(Category category); // 定义save()方法,用于新增Category对象,返回值表示影响的行数

    @Delete(" delete from category_ where id= #{id} ") // 使用@Delete注解指定SQL删除语句
    public void delete(int id); // 定义delete()方法,用于删除指定id的Category对象

    @Select("select * from category_ where id= #{id} ") // 使用@Select注解指定SQL查询语句
    public Category get(int id); // 定义get()方法,用于查询指定id的Category对象

    @Update("update category_ set name=#{name} where id=#{id} ") // 使用@Update注解指定SQL更新语句
    public int update(Category category); // 定义update()方法,用于更新Category对象,返回值表示影响的行数

}

完善控制器(含分页插件“PageHelper”详解):

CategoryController.java:

package com.how2java.springboot.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.how2java.springboot.mapper.CategoryMapper;
import com.how2java.springboot.pojo.Category;

@Controller // 声明该类为Spring MVC的Controller类,用于处理HTTP请求和响应。
public class CategoryController {
    @Autowired 
    private CategoryMapper categoryMapper; // 自动注入CategoryMapper对象

    @RequestMapping("/addCategory")
    public String addCategory(Category c) throws Exception {
        categoryMapper.save(c); // 调用CategoryMapper的save()方法保存Category对象
        return "redirect:listCategory"; // 重定向到listCategory请求
    }

    @RequestMapping("/deleteCategory")
    public String deleteCategory(Category c) throws Exception {
        categoryMapper.delete(c.getId()); // 调用CategoryMapper的delete()方法删除指定id的Category对象
        return "redirect:listCategory"; // 重定向到listCategory请求
    }

    @RequestMapping("/updateCategory")
    public String updateCategory(Category c) throws Exception {
        categoryMapper.update(c); // 调用CategoryMapper的update()方法更新Category对象
        return "redirect:listCategory"; // 重定向到listCategory请求
    }

    @RequestMapping("/editCategory")
    public String editCategory(int id, Model m) throws Exception {
        Category c = categoryMapper.get(id); // 调用CategoryMapper的get()方法查询指定id的Category对象
        m.addAttribute("c", c); // 将查询结果设置到Model中作为属性
        return "editCategory"; // 返回逻辑视图名
    }

    @RequestMapping("/listCategory")
    public String listCategory(Model m, @RequestParam(value = "start", defaultValue = "0") int start,
            @RequestParam(value = "size", defaultValue = "5") int size) throws Exception {
        PageHelper.startPage(start, size, "id desc"); // 使用分页插件PageHelper设置分页参数
        List<Category> cs = categoryMapper.findAll(); // 调用CategoryMapper的findAll()方法查询所有Category对象并返回结果集
        PageInfo<Category> page = new PageInfo<>(cs); // 使用PageInfo对结果集进行包装,以支持更多分页信息的获取
        m.addAttribute("page", page); // 将查询结果设置到Model中作为属性
        return "listCategory"; // 返回逻辑视图名
    }

}

在这个控制器中,CUD的路由及其方法是相对比较简单,这里来说一说我对R(查询/分页)路由及其方法的理解:

  @RequestMapping("/listCategory")
    public String listCategory(Model m, 
    		@RequestParam(value = "start", defaultValue = "0") int start,
            @RequestParam(value = "size", defaultValue = "5") int size) throws Exception {
        PageHelper.startPage(start, size, "id asc"); // 使用分页插件PageHelper设置分页参数
        List<Category> cs = categoryMapper.findAll(); // 调用CategoryMapper的findAll()方法查询所有Category对象并返回结果集
        PageInfo<Category> page = new PageInfo<>(cs); // 使用PageInfo对结果集进行包装,以支持更多分页信息的获取
        m.addAttribute("page", page); // 将查询结果设置到Model中作为属性
        return "listCategory"; // 返回逻辑视图名
    }

上述代码中,

PageHelper.startPage(start, size, "id asc");

表示从以size数量的元组为一页的第start页开始,采用按id升序的方式展示到前端页面上。

			@RequestParam(value = "start", defaultValue = "0") int start,
            @RequestParam(value = "size", defaultValue = "5") int size

这段代码声明了参数start和size,并设置了他们的默认值分别为0和5。

List<Category> cs = categoryMapper.findAll(); // 调用CategoryMapper的findAll()方法查询所有Category对象并返回结果集
PageInfo<Category> page = new PageInfo<>(cs); // 使用PageInfo对结果集进行包装,以支持更多分页信息的获取

第一行代码中,我们调用 categoryMapper.findAll() 方法查询数据库中的所有 Category 记录。这个方法可能会返回大量数据,如果直接全部查询出来,就可能会导致内存溢出等问题。因此,在实际应用中,我们通常会将查询结果进行分页,以提高系统性能和用户体验。

在第二行代码中,我们使用 PageInfo 对查询结果进行包装,并将其保存到 page 变量中。PageInfo 是 MyBatis 分页插件 PageHelper 提供的一个分页数据类,可以将查询结果封装成一个带有分页信息的对象。在这里,我们将查询结果 cs 传入 PageInfo 的构造函数中,并通过泛型 指定了查询结果的类型。MyBatis 会根据查询参数和分页设置,自动计算出总页数、当前页码等分页信息,并将其保存在 PageInfo 对象中。

由于我们是使用插件进行分页的,因此我们需要对插件进行配置:
PageHelperConfig.java:

package com.how2java.springboot.config;

import java.util.Properties;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.pagehelper.PageHelper;

@Configuration //该类为配置类
public class PageHelperConfig {

    @Bean //创建一个Bean实例,用于注入PageHelper对象到容器中
    public PageHelper pageHelper() {
        PageHelper pageHelper = new PageHelper(); //创建一个PageHelper对象

        Properties p = new Properties(); //创建Properties对象,用于设置PageHelper的属性
        p.setProperty("offsetAsPageNum", "true"); //设置offsetAsPageNum属性为true
        p.setProperty("rowBoundsWithCount", "true"); //设置rowBoundsWithCount属性为true
        p.setProperty("reasonable", "true"); //设置reasonable属性为true

        pageHelper.setProperties(p); //将设置好的属性赋值给PageHelper对象

        return pageHelper; //返回PageHelper对象
    }
}

这份代码我探明的目前只有这份代码本身,@Configuration 和@Bean注解,以及 p.setProperty(“reasonable”, “true”)。

  • 这份代码配合两个注解,实现IOC和DI
  • p.setProperty(“reasonable”, “true”)用于启用合理化策略,处理一些边界情况。例如当页码小于1时,会将页码强制设为1;当页码大于总页数时,会将页码强制设为总页数。这样可以保证查询结果的准确性和用户体验。

其他部分经我测试,在该案例中是可有可无的。

更新:

p.setProperty("rowBoundsWithCount", "true");

这行代码使得在查询结果进行分页时,不一次性查完全部数据,为cpu增加负担,以提高系统性能和用户体验。

运行查看:

运行application.java后,在浏览器中访问http://127.0.0.1:8080/listCatgory
在这里插入图片描述

4.SpringBoot+MyBatis(配置文件方式):

参考how2j的教程可以比较容易地实现。
这里主要讲一讲我对注解方式xml方式的理解(区别和联系):

MyBatis 和 Spring Boot 结合方式主要有两种:使用注解方式和使用 XML 配置文件方式。它们的区别和联系如下:

  1. 区别
  • 注解方式:使用 @MapperScan@Mapper 注解将 MyBatis Mapper 接口和相应的 XML 文件进行关联,使得 Spring Boot 程序能够自动扫描并加载这些 Mapper 接口实现。不需要额外的配置文件,具有简洁的代码结构和易于维护的特点。
  • XML 配置文件方式:手动编写 MyBatis 的 Mapper XML 文件,在其中定义 SQL 映射关系以及查询逻辑等信息。在 Spring Boot 的配置文件中进行相应的配置,例如指定 Mapper 文件的位置、数据源等信息。需要手动编写和维护 XML 文件,但更加灵活,支持自定义 SQL 语句和查询逻辑。
  1. 联系
  • 共同点:无论是注解方式还是 XML 配置文件方式,都可以将 MyBatis 和 Spring Boot 进行无缝集成,实现对数据库的访问和操作。
  • 相互补充:两种方式各有优劣,使用时可以根据项目需求和个人习惯进行选择。在实际项目中,往往会同时使用两种方式,以满足不同场景的需要。例如,可以使用注解方式实现一些简单的 SQL 查询和更新操作,而对于复杂的 SQL 逻辑,则可以使用 XML 配置文件方式进行定义和管理。

SpringBoot出现,便是为了简化配置,从这一点上来说,注解方式是更符合SpringBoot的设计理念的。但就耦合程度而言,注解却是相对紧耦合的。可见,在项目中选择哪种方式,需要考虑项目需求、代码规模、团队习惯等多方面因素,综合评估后做出更为合适的选择。

5.解决“Whitelabel Error Page”问题:

在运行一个接一个的基于SpringBoot的项目后,由于不正确的操作,可能会出现Whitelabel Error Page的报错提示

在这里插入图片描述

这是由于端口被占用导致的

在这里插入图片描述

上面是一个活动连接列表,在cmd中输入netstat可查询,每一列的意思如下:

  • 协议:连接使用的协议,如TCP或UDP。
  • 本地地址:本地计算机的IP地址和端口号。
  • 外部地址:连接到的远程计算机的IP地址和端口号。
  • 状态:连接的当前状态,如ESTABLISHED表示连接已经建立,TIME_WAIT表示连接已经关闭但是仍在等待一些数据包。

解决方法:
(1)方式一:
每一次启动一个配备内置Tomcat的Java程序前,手动关闭,上一个应用程序,使它不再占用端口

在这里插入图片描述

(2)方式二:
重启Eclipse即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/629931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅结代码混淆2

文章目录 SMC 自解码什么是SMC&#xff1f;原理示例动调 &#xff4d;ov混淆 SMC 自解码 什么是SMC&#xff1f; 简而言之&#xff0c;就是程序中的部分代码在运行之前被加密成一段数据&#xff0c;不可反编译&#xff0c;通过程序运行后执行相关的解码功能&#xff0c;对加密…

Nginx搭建Https反向代理,使用阿里云免费SSL证书 - Docker

Docker安装Nginx - 需要有域名 没有docker需提前安装docker&#xff0c;不知怎么安装的请自行百度。 1、拉取镜像 docker pull nginx2、去阿里云或者其他云服务提供商申请免费证书&#xff0c;申请到之后下载下来&#xff0c;上传到服务器 # 创建nginx-proxy目录 mkdir ngi…

软考A计划-系统架构师-官方考试指定教程-(13/15)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

IP签名档PHP开源版:轻松打造网站个性签名档

今天&#xff0c;我们将为大家介绍一个有趣的IP签名档项目。通过将源代码部署在服务器上&#xff0c;您可以轻松地为自己的社交媒体、论坛等地创建一个独特的签名档&#xff0c;使您的网站更加出彩&#xff01; 接下来&#xff0c;我们将详细向大家展示如何搭建PHP开源版IP签名…

ASP.NET Core Web API入门之一:创建新项目

ASP.NET Core Web API入门之一&#xff1a;创建新项目 一、引言二、创建新项目三、加入Startup类&#xff0c;并替换Program.cs内容四、编辑Program.cs代码五、修改控制器的路由六、运行项目 一、引言 最近闲着&#xff0c;想着没真正从0-1开发过ASP.NET Core Web API的项目&a…

SpringMVC原理分析 | Hello程序

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; SpringMVC Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架&#xff0c;本质上相当于 Servlet&#xff1b; 拥有结构最清晰的 ServletJSPJav…

uni-app APP、html引入html2canvas截图以及截长图

下载安装html2canvas 方式一&#xff0c;https://www.bootcdn.cn/ CDN网站下载html2canvas插件 这里下载后放在测项目目录common下面 页面中引入 方式二、npm方式安装html2canvas 1、npm方式下载 npm i html2canvas2、引入html2canvas import html2canvas from html2can…

linux系统CAN驱动问题分析

在TI sam3354芯片上&#xff0c;使用3.13及4.19版内核&#xff0c;编译CAN驱动&#xff0c;加载启动后&#xff0c;查看有CAN设备&#xff0c;但无法直接使用ifconfig操作CAN设备&#xff0c;以下简单分析下问题。 加载驱动后&#xff0c;查看网络设备&#xff1a; 可以看到有…

分布式项目15 用户注册,单点登陆,用户退出dubbo来实现

用户注册 分析&#xff1a;当用户填写完成注册信息之后,将请求发送给前台服务器.之后前台消费者利用dubbo框架实现RPC调用。之后将用户信息传递给jt-sso服务提供者.之后完成数据的入库操作。 01.页面url分析 02.查看页面JS $.ajax({ type : "POST", url : "/…

煤矿安全防范,DTU为采矿过程提供实时数据支持

在当今快节奏的时代&#xff0c;采矿行业为我们提供了丰富的资源。然而&#xff0c;随着采矿作业的不断扩大和复杂化&#xff0c;我们也面临着一系列潜在的挑战。其中&#xff0c;数据传输和安全问题尤为突出。 想象一下&#xff0c;在一个繁忙的矿山中&#xff0c;海量的数据需…

让软件研发可视化可量化,华为云CodeArts持续加速企业研发转型

导读&#xff1a;软件开发工具从未像今天这样重要。 “没有度量&#xff0c;就没有管理。” (If you can’t measure it, you can’t manage it.) 管理学大师彼得德鲁克的话时刻提醒人们&#xff0c;度量是管理的必要条件。 在高科技领域&#xff0c;研发投入是企业核心竞争力的…

Linux常用命令——grep命令

在线Linux命令查询工具 grep 强大的文本搜索工具 补充说明 grep&#xff08;global search regular expression(RE) and print out the line&#xff0c;全面搜索正则表达式并把行打印出来&#xff09;是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&…

【MySQL数据库 | 第十二篇】:约束

约束&#xff1a; 在MySQL中&#xff0c;约束是一种限制数据表中列值的规定。保证数据库中的数据正确&#xff0c;有效性和完整性。MySQL中的约束有以下几种&#xff1a; 1. 主键约束&#xff08;Primary Key Constraint&#xff09;&#xff1a;主键是用于唯一标识表中每行记…

国内强大的智能语言模型AI

​ Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 前言 环境列表 视频教程 1.飞书设置 2.克隆feishu-chatgpt项目 3.配置config.yaml文件 4.运行feishu-chatgpt项目 5.安装cpolar内网穿透 6.固定公网地址 7.机器人权…

chatgpt赋能python:Python文件目录切换:简单易用的方法

Python文件目录切换&#xff1a;简单易用的方法 Python语言可以轻松地处理文件和目录。使用Python的os库可以方便地操作文件系统。Python在os库中提供了许多可以轻松完成文件和目录操作的函数&#xff0c;其中之一是os.chdir。os.chdir函数用于更改当前的工作目录。 为什么需…

使用阿里云OSS实现图片文件上传

说明&#xff1a;注册用户时&#xff0c;经常会用到上传头像。文件的上传/接收与一般文本数据不同。 一、创建Demo页面 先准备一个Demo页面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>图片上传…

第三章 三段论:所有,有的。

第三章 三段论&#xff1a;所有&#xff0c;有的。 第一节 三段论-推结论 题-三段论-结构-推结论&#xff1a;所有A是B&#xff1b;所有B是C&#xff1b;得&#xff1a;所有A是C。&#xff08;最简单的模型&#xff09; 4.所有高明的管理者都懂得关心雇员福利的重要性&…

Linux目录结构(与window目录结构对比+绝对路径和相对路径)

一、Linux目录结构 Linux目录结构是一个标准化的文件系统层次结构&#xff0c;非常有组织性并且易于管理。而与Windows 操作系统不同&#xff0c;Linux将所有文件和设备都组织在一个单一的根目录下。以下是Linux的标准目录结构&#xff1a; /&#xff1a;根目录&#xff0c;包含…

<DB2>《DB2数据库健康检查》第3部分

《DB2数据库健康检查》第3部分 2 数据库对象检查2.12 检查是否需要对表和索引进行runstats(30天未作统计更新)2.13 检查表和索引是否需要重组2.14 查看表空间所在裸设备权限2.15 查看数据库备份进度 2 数据库对象检查 2.12 检查是否需要对表和索引进行runstats(30天未作统计更…

递归sql查询完整科目名称

已知表 科目编号 科目名称 1001 1001 现金 1002 1002 银行存款 10020100 0100 工商银行存款 100201000001 0001 工行重庆路支行 10020200 0200 建设银行存款 100202000001 0001 建行铁北支行 需要整理成 科目编号 科目称 科目全称 1001 现金 现金 1002 银行存款 银行存款 …