Spring MVC-05循序渐进之数据绑定和form标签库(下) 实战从0到1

简介: Spring MVC-05循序渐进之数据绑定和form标签库(下) 实战从0到1

概述


Spring MVC-05循序渐进之数据绑定和form标签库(上) 博文中我们学习了数据绑定和form标签库,那我们来写一个小demo练习下吧。


功能概述


假设有个Artisan管理页面,先抛开花里胡哨的前端,我们用最丑最简单的方式实现,来体会下Spring MVC数据绑定及表单的操作过程 。如下图


20180208223457723.jpg


搭建SpringMVC Maven工程


20180131101539731.jpg


pom.xml


添加Maven依赖,主要的依赖包是spring-webmvc-${version},这里我们采用4.3.9版本,同时使用JDK7来编译

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.artisan</groupId>
    <artifactId>chapter05a</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>chapter05a Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>chapter05a</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>



部署描述符web.xml


配置DispatcherServlet,指定SpringMVC配置文件的路径,同时为避免中文乱码配置filter ,指定CharacterEncodingFilter为UTF-8。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/springmvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>    
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
     <!-- 避免中文乱码 -->
    <filter>  
        <filter-name>characterEncodingFilter</filter-name>  
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
        <init-param>  
            <param-name>encoding</param-name>  
            <param-value>UTF-8</param-value>  
        </init-param>  
        <init-param>  
            <param-name>forceEncoding</param-name>  
            <param-value>true</param-value>  
        </init-param>  
    </filter>  
    <filter-mapping>  
        <filter-name>characterEncodingFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping> 
</web-app>


配置Spring MVC配置文件


通过context:component-scan 结合注解,扫描bean 。

同时配置静态资源文件过滤,以及视图解析器。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd     
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 扫描Controller -->
    <context:component-scan base-package="com.artisan.springmvc.controller"/>
    <!-- 扫描Service -->
    <context:component-scan base-package="com.artisan.springmvc.service"/>
    <!-- 静态资源文件 -->
    <mvc:annotation-driven/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/*.jsp" location="/"/>
    <!-- 视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

日志配置文件


先简单配置下 ,启动Spring容器的时候不报错即可。

log4j.rootLogger=INFO,A1
log4j.logger.org.springframework=info
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n


Domain类

根据我们的构想及页面原型,这个Demo中的domain类Artisan,应该有如下几个属性

    private long id;
    private String name;
    private String code;
    private String sex;
    private Org org;


有个类型为Org 的org属性,其中 Org有如下2个属性

private int orgId;
    private String orgName;


package com.artisan.springmvc.domian;
public class Artisan {
    private long id;
    private String name;
    private String code;
    private String sex;
    private Org org;
    /**
     * 
     * 创建一个新的实例 Artisan.
     * 
     * @param id
     * @param name
     * @param code
     * @param sex
     * @param org
     */
    public Artisan(long id, String name, String code, String sex, Org org) {
        super();
        this.id = id;
        this.name = name;
        this.code = code;
        this.sex = sex;
        this.org = org;
    }
    /**
     * 
    * 默认构造函数
    *
     */
    public Artisan() {
        super();
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Org getOrg() {
        return org;
    }
    public void setOrg(Org org) {
        this.org = org;
    }
}
package com.artisan.springmvc.domian;
public class Org {
    private int orgId;
    private String orgName;
    /**
     * 
     * 创建一个新的实例 Org. 默认的构造函数需要有,否则 org.apache.jasper.JasperException:
     * org.springframework.beans.NullValueInNestedPathException: Invalid
     * property 'org' of bean class [com.artisan.springmvc.domian.Artisan]:
     * Could not instantiate property type [com.artisan.springmvc.domian.Org] to
     * auto-grow nested property path; nested exception is
     * org.springframework.beans.BeanInstantiationException: Failed to
     * instantiate [com.artisan.springmvc.domian.Org]: Is it an abstract class?;
     * nested exception is java.lang.InstantiationException:
     * com.artisan.springmvc.domian.Org
     *
     * 
     */
    public Org() {
        super();
    }
    /**
     * 
     * 创建一个新的实例 Org.
     * 
     * @param orgId
     * @param orgName
     */
    public Org(int orgId, String orgName) {
        super();
        this.orgId = orgId;
        this.orgName = orgName;
    }
    public int getOrgId() {
        return orgId;
    }
    public void setOrgId(int orgId) {
        this.orgId = orgId;
    }
    public String getOrgName() {
        return orgName;
    }
    public void setOrgName(String orgName) {
        this.orgName = orgName;
    }
}


Controller类


第一步,首先获取一个Artisan列表, 个人习惯先开发Controller


按照设计输入http://ip:port/context/artisan/artisanList 可获取全部的Artisan数据


@Controller
@RequestMapping("/artisan")
public class ArtisanController {
    private static final Logger logger  = Logger.getLogger(ArtisanController.class);
    private ArtisanService artisanService;
    public ArtisanService getArtisanService() {
        return artisanService;
    }
    /**
     * 
    * @Title: setArtisanService  
    * @Description: 通过 @Autowired注入ArtisanService
    * @param @param artisanService    参数  
    * @return void    返回类型  
    * @throws
     */
    @Autowired
    public void setArtisanService(ArtisanService artisanService) {
        this.artisanService = artisanService;
    }
    @RequestMapping(value="/artisanList",method=RequestMethod.GET)
    public String getAllArtisans(Model model){
        logger.info("getAllArtisans called....");
        List<Artisan> artisanList = artisanService.getArtisans();
        // 添加到Model中,以便前台能访问到
        model.addAttribute("artisanList", artisanList);
        return "ArtisanList";
    }
}

通过在类上标注注解@Controller ,配合component-scan扫描,使其成为一个控制器,然后标注了@RequestMapping(“/artisan”),在类层级上标注了请求路径,这个控制器中所有的方法都基于/artisan。


通过@Autowired自动注入service,然后通过artisanService.getArtisans()获取模拟的artisanList


紧接着将数据添加到Model中,以便前台能访问到 model.addAttribute(“artisanList”, artisanList);


最后返回了一个视图ArtisanList,结合SpringMVC配置文件中的视图解析器,会转发到/WEB-INF/jsp/目录下的ArtisanList.jsp


Service类

目前只有一个获取全部数据的接口,后续根据功能逐个增加

package com.artisan.springmvc.service;
import java.util.List;
import com.artisan.springmvc.domian.Artisan;
public interface ArtisanService {
    // 获取所有的Artisan
    List<Artisan> getArtisans();
}


接口实现类

package com.artisan.springmvc.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.artisan.springmvc.domian.Artisan;
import com.artisan.springmvc.domian.Org;
/**
 * 
 * @ClassName: ArtisanServiceImpl
 * @Description: 通过@Service标注的服务层 ,
 * @author Mr.Yang
 * @date 2018年1月30日
 *
 */
@Service
public class ArtisanServiceImpl implements ArtisanService {
    /*
     * this implementation is not thread-safe
     */
    List<Artisan> artisanList = null;
    String sex = null;
    /**
     * 
     * 创建一个新的实例 ArtisanServiceImpl的同时初始化模拟数据
     *
     */
    public ArtisanServiceImpl() {
        super();
        // 初始化模式数据
        artisanList = new ArrayList<Artisan>();
        for (int i = 0; i < 10; i++) {
            if (i%2 == 0) {
                sex = "男";
            }else {
                sex="女";
            }
            artisanList.add(new Artisan(i, "Artisan" + i, "ATSCode" + i, sex, new Org(i, "org" + i)));
        }
    }
    @Override
    public List<Artisan> getArtisans() {
        return artisanList;
    }
}


视图


引入c标签,然后对后台Model中的artisanList进行遍历显示数据。 有CSS修饰样式。

ArtisanList.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Artisan List</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body>
<div id="global">
<h1>Artisan List</h1>
<p>
    <a href='<c:url value="/artisan/artisan_input"/>'>Add Artisan</a>
</p>
<table border="1" cellspacing="0">
<tr>
    <th align="center">OrgName</th>
    <th align="center">ArtisanName</th>
    <th align="center">Code</th>
    <th align="center">Sex</th>
    <th align="center" colspan="2">Operation</th>
</tr>
<!-- var要循环集合的别名 -->
<c:forEach items="${artisanList}" var="artisan" varStatus="status">
    <tr <c:if test="${status.count%2==0}">bgcolor="#7CCD7C"</c:if> align="center">
        <td>${artisan.org.orgName}</td>
        <td>${artisan.name}</td>
        <td>${artisan.code}</td>
        <td>${artisan.sex}</td>
        <td><a href>Edit</a></td>
    </tr>
</c:forEach>
</table>
</div>
</body>
</html>


artisan_list测试


启动tomcat,然后访问

http://localhost:8080/chapter05a/artisan/artisanList 即可获取全部的ArtisanList


20180208224821342.jpg


artisan_add


我们来分析一下artisan_add的逻辑

1. 通过点击ArtisanList.jsp页面上的Add Artisan 超链接标签,使用JSTL标记的URL解决路径访问的问题,跳转到添加页面

2. 再添加页面中加载Org下拉列表,输入信息后,提交触发保存Artisan的操作

3. 后台保存完成后 ,重定向到ArtisanList,展示数据。


编写超链接标签中对应的uri


<a href='<c:url value="/artisan/artisan_input"/>'>Add Artisan</a>


使用JSTL标记的URL解决路径访问的问题, 因为我们在web.xml中配置拦截所有的请求,因此这个请求会被DispatcherServlet拦截,映射到如下的方法中


Controller映射方法

/**
     * 
    * @Title: inputArtisan  
    * @Description: 进入inputArtisan的页面 
    * @param @return    参数  
    * @return String    返回类型  
    * @throws
     */
    @RequestMapping(value="/artisan_input")
    public String inputArtisan(Model model){
        // 获取全部的org
        List<Org> orgs = artisanService.getAllOrgs();
        // 加载org到Model中以便前台展示
        model.addAttribute("orgs", orgs);
        // 前台form  commandName为artisan,因此必须保证model中存在一个artisan
        model.addAttribute("artisan",new Artisan());
        return "AddArtisan";
    }



因为添加页面需要展示org列表,所以必须从后台加载全部的org,放到model中,确保前台页面可以通过表达式获取到对应的数据。 同时,前台添加Artisan的form ,打算加入commandName属性方便识别, 如下 form:form commandName="artisan" commandName 为artisan,如果该属性存在,则必须在返回包含该表单的视图的请求处理方法中添加对应的模型属性.


返回的字符串 AddArtisan,SpringMVC会根据视图解析器的配置规则

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

映射到/WEB-INF/jsp/AddArtisan.jsp


AddArtisan.jsp

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Add Artisan Form</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body>
<div id="global">
<form:form commandName="artisan" action="artisan_add" method="post">
    <fieldset>
        <legend>Add an Artisan</legend>
        <p>
            <label for="orgs">orgName: </label>
            <form:select id="org" path="org.orgId" 
                items="${orgs}"  
                itemValue="orgId" 
                itemLabel="orgName"/>
        </p>
        <p>
            <label for="name">name: </label>
            <form:input id="name" path="name"/>
        </p>
        <p>
            <label for="code">code: </label>
            <form:input id="code" path="code"/>
        </p>
        <p>
            <label for="sex">sex: </label>
            <form:input id="sex" path="sex"/>
        </p>
        <p id="buttons">
            <input id="reset" type="reset" tabindex="4">
            <input id="submit" type="submit" tabindex="5" 
                value="Add Artisan">
        </p>
    </fieldset>
</form:form>
</div>
</body>
</html>


Org的下拉列表采用form的select标签,点击超链接跳转页面的方法中,调用后端的方法获取全部的orgList,同时存放到model中,便于前端展示。 同时绑定了path=”org.orgId” ,后端提供根据页面传入的orgId获取Org的接口及实现类

实现类如下

@Override
    public Org getOrg(int orgId) {
        for (Org org:orgList) {
            if (orgId == org.getOrgId()) {
                return org;
            }
        }
        return null;
    }

根据前端选择orgId, 返回对应的org实体类。

然后设置给artisan, 最后调用服务层的方法保存artisan到list中,最后重定向到list列表

代码如下

@RequestMapping(value="/artisan_add",method=RequestMethod.POST)
    public String addArtisan(@ModelAttribute Artisan artisan){
        logger.info("addArtisan called...");
        // 获取页面的数据
        logger.info("orgId:" + artisan.getOrg().getOrgId());
        logger.info("Name:" + artisan.getName());
        logger.info("Code:" + artisan.getCode());
        logger.info("Sex:" + artisan.getSex());
        //根据前台传入绑定的orgId,获取Org
        Org org = artisanService.getOrg(artisan.getOrg().getOrgId());
        // 设置org
        artisan.setOrg(org);
        // 保存artisan
        artisanService.addArtisan(artisan);
        // 跳转到list页面
        return "redirect:/artisan/artisan_list";
    }


测试结果


20180208225016607.jpg


Edit Artisan


下面我们来梳理一下编辑的逻辑

1. 点击Edit按钮,进入编辑页面,这个页面需要将对应的数据加载显示,然后提供用户编辑

2. 用户点击UPDATE按钮后,提交到后端更新数据,然后重定向到list页面


编写uri


第一步展示list的时候,我们已经从后端加载了artisan的id ,所以编辑的时候根据artisan#id去编辑,这样href如下

<a href="artisan_edit/${artisan.id}">Edit</a>


编写映射方法

根据artisan_edit/${artisan.id} 映射到如下方法

/**
     * 
    * @Title: editArtisan  
    * @Description: 跳转到编辑Artisan页面  
    * @param @param model
    * @param @param id
    * @param @return    参数  
    * @return String    返回类型  
    * @throws
     */
    @RequestMapping(value="/artisan_edit/{id}")
    public String editArtisan(Model model,@PathVariable long  id){
        logger.info("Artisan ID:" + id);
        // 加载Org全部数据 用于选择
        List<Org> orgList = artisanService.getAllOrgs();
        // 添加到model,以便前台访问
        model.addAttribute("orgList", orgList);
        // 根据传入的id,获取对应的artisan信息 用于编辑页面展示Artisan信息
        Artisan artisan = artisanService.getArtisanById(id);
        // 添加到model,以便前台访问
        model.addAttribute("artisan", artisan);
        return "EditArtisan";
    }


编写EditArtisan.jsp

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
//获得本项目的地址(例如: http://localhost:8080/domain/)赋值给basePath变量 
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
// 将 "项目路径basePath" 放入pageContext中,待以后用EL表达式读出。 
pageContext.setAttribute("basePath",basePath); 
%>
<!DOCTYPE HTML>
<html>
<head>
<title>Edit Artisan Form</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body>
<div id="global">
<form:form commandName="artisan" action="${pageScope.basePath}/artisan/artisan_update" method="post">
    <fieldset>
        <legend>Edit Artisan</legend>
        <form:hidden path="id"/>
        <p>
            <label for="orgs">orgName: </label>
            <form:select id="org" path="org.orgId" 
                items="${orgList}"  
                itemValue="orgId" 
                itemLabel="orgName"/>
        </p>
        <p>
            <label for="name">name: </label>
            <form:input id="name" path="name"/>
        </p>
        <p>
            <label for="code">code: </label>
            <form:input id="code" path="code"/>
        </p>
        <p>
            <label for="sex">sex: </label>
            <form:input id="sex" path="sex"/>
        </p>
        <p id="buttons">
            <input id="reset" type="reset" tabindex="4">
            <input id="submit" type="submit" tabindex="5" 
                value="Update Artisan">
        </p>
    </fieldset>
</form:form>
</div>
</body>
</html>


update映射方法

点击提交后,action=”${pageScope.basePath}/artisan/artisan_update” ,映射

    @RequestMapping(value="/artisan_update",method=RequestMethod.POST)
    public String artisanUpdate(@ModelAttribute Artisan artisan){
        logger.info("artisanUpdate called");
        logger.info("artisan orgId:" + artisan.getOrg().getOrgId());
        logger.info("artisan Id:" + artisan.getId());
        logger.info("artisan Name:" + artisan.getName());
        logger.info("artisan Sex:" + artisan.getSex());
        logger.info("artisan Code:" + artisan.getCode());
        // 根据orgId获取org
        Org org = artisanService.getOrg(artisan.getOrg().getOrgId());
        logger.info("Org Name :" + org.getOrgName());
        artisan.setOrg(org);
        // 更新数据
        artisanService.updateArtisan(artisan);
        return "redirect:/artisan/artisan_list";
    }


测试


修改一条数据,如下

20180208230749199.jpg

20180208230603421.jpg


总结

至此,一个简单的实例已经编写完毕,重点是体会思路及spring mvc 及form的应用。


源码

代码已提交到github

https://github.com/yangshangwei/SpringMvcTutorialArtisan

相关文章
|
27天前
|
JSON 前端开发 Java
【SpringMVC】基础入门实战(3)
SpringMVC获取Header,返回静态页面,返回数据(Controller),返回数据@ResponseBody,返回HTML代码片段,返回JSON,设置状态码,设置Header
|
3月前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
502 6
|
3月前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
206 2
|
3月前
|
Java 数据库连接 Spring
【2021Spring编程实战笔记】Spring开发分享~(下)
【2021Spring编程实战笔记】Spring开发分享~(下)
39 1
|
3月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
93 0
|
3月前
|
XML Java 数据库连接
【2020Spring编程实战笔记】Spring开发分享~(上)
【2020Spring编程实战笔记】Spring开发分享~
64 0
|
5月前
|
Java API UED
【实战秘籍】Spring Boot开发者的福音:掌握网络防抖动,告别无效请求,提升用户体验!
【8月更文挑战第29天】网络防抖动技术能有效处理频繁触发的事件或请求,避免资源浪费,提升系统响应速度与用户体验。本文介绍如何在Spring Boot中实现防抖动,并提供代码示例。通过使用ScheduledExecutorService,可轻松实现延迟执行功能,确保仅在用户停止输入后才触发操作,大幅减少服务器负载。此外,还可利用`@Async`注解简化异步处理逻辑。防抖动是优化应用性能的关键策略,有助于打造高效稳定的软件系统。
88 2
|
5月前
|
JSON Java API
解码Spring Boot与JSON的完美融合:提升你的Web开发效率,实战技巧大公开!
【8月更文挑战第29天】Spring Boot作为Java开发的轻量级框架,通过`jackson`库提供了强大的JSON处理功能,简化了Web服务和数据交互的实现。本文通过代码示例介绍如何在Spring Boot中进行JSON序列化和反序列化操作,并展示了处理复杂JSON数据及创建RESTful API的方法,帮助开发者提高效率和应用性能。
244 0
|
5月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
412 0
|
5月前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
85 0