Spring Boot项目学习08之个人中心设置功能模块

1.用户信息页面跳转及信息展示

用户模块不只有登录、注册功能,还包括用户信息展示、头像上传、用户信息修改、安全退出等功能。用户信息功能的主要实现步骤为三步:

  • 用户信息页面跳转请求实现
  • 用户信息页面样式设置
  • 用户信息页面信息展示

1.1 Controller 处理跳转请求

在 BBSUserController.java 控制器中新增用户信息跳转处理功能。该方法用于处理 /userSet 请求,即用户信息页面的跳转处理,由于用户信息页面需要展示的是登录者的用户信息,而登录者的信息已经在登录成功后,放入 session 对象中,所以这里并不需要进行额外的查询操作,将 session 对象中的对象取出并放入 request 域中即可。之后 return 视图语句,跳转到 templates/user 目录下的 set.html 中。

    /**
     * 用户信息页面跳转
     * @param request
     * @return
     */
    @GetMapping("/userSet")
    public String userSetPage(HttpServletRequest request) {
        // 从session中获取登陆用户的信息
        BBSUser currentUser = (BBSUser) request.getSession().getAttribute(Constants.USER_SESSION_KEY);
        request.setAttribute("bbsUser", currentUser);
        return "user/set";
    }

1.2 配置登陆拦截器

这里还需要在拦截器配置中,将 /userSet 请求进行拦截设置,即登录成功后才可以访问用户信息页面,否则会跳转至登录页面。

public void addInterceptors(InterceptorRegistry registry) {
        // 登陆拦截
        registry.addInterceptor(myBBSLoginInterceptor)
                .excludePathPatterns("/register")
                .excludePathPatterns("/login")
                .addPathPatterns("/index")
                .addPathPatterns("/userSet");
    }

1.3 创建用户中心设置页面

使用 Thymeleaf 语法读取用户信息,包括用户头像、用户名等内容,代码为:

th:src="@{${bbsUser.headImgUrl}}" 
th:value="${bbsUser.loginName}"
th:value="${bbsUser.location}" 
th:text="${bbsUser.introduce}"

新建 set.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="header::head-fragment('基本设置')">
</head>
<body>
<div th:replace="header::header-fragment"></div>

<div class="layui-container fly-marginTop fly-user-main">
    <ul class="layui-nav layui-nav-tree layui-inline" lay-filter="user">
        <li class="layui-nav-item">
            <a th:href="@{${'/userCenter/'+bbsUser.userId}}">
                <i class="layui-icon">&#xe609;</i>
                我的主页
            </a>
        </li>
        <li class="layui-nav-item">
            <a th:href="@{/myCenter}">
                <i class="layui-icon">&#xe612;</i>
                用户中心
            </a>
        </li>
        <li class="layui-nav-item layui-this">
            <a th:href="@{/userSet}">
                <i class="layui-icon">&#xe620;</i>
                基本设置
            </a>
        </li>
    </ul>

    <div class="fly-panel fly-panel-user" pad20>
        <div class="layui-tab layui-tab-brief" lay-filter="user">
            <ul class="layui-tab-title" id="LAY_mine">
                <li class="layui-this" lay-id="info">我的资料</li>
                <li lay-id="avatar">头像</li>
                <li lay-id="pass">密码</li>
            </ul>
            <div class="layui-tab-content" style="padding: 20px 0;">
                <div class="layui-form layui-form-pane layui-tab-item layui-show">
                    <form method="post" id="updateInfoForm" onsubmit="return false;" action="##">
                        <div class="layui-form-item">
                            <label for="loginName" class="layui-form-label">邮箱</label>
                            <div class="layui-input-inline">
                                <input type="text" id="loginName" name="loginName"
                                       autocomplete="off" th:value="${bbsUser.loginName}" disabled class="layui-input">
                            </div>
                            <div class="layui-form-mid layui-word-aux">登录邮箱不可更改</div>
                        </div>
                        <div class="layui-form-item">
                            <label for="nickName" class="layui-form-label">昵称</label>
                            <div class="layui-input-inline">
                                <input type="text" id="nickName" name="nickName" required lay-verify="required"
                                       autocomplete="off" th:value="${bbsUser.nickName}" class="layui-input">
                            </div>
                            <div class="layui-form-mid layui-word-aux">支持2-8位的英文和数字昵称</div>
                        </div>
                        <div class="layui-form-item">
                            <label for="userGender" class="layui-form-label">性别</label>
                            <div class="layui-input-inline">
                                <select name="userGender" id="userGender">
                                    <option value="1" th:selected="${bbsUser.gender==''} ?true:false"></option>
                                    <option value="2" th:selected="${bbsUser.gender==''} ?true:false"></option>
                                </select>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label for="location" class="layui-form-label">城市</label>
                            <div class="layui-input-inline">
                                <input type="text" id="location" name="location" autocomplete="off"
                                       th:value="${bbsUser.location}"
                                       class="layui-input">
                            </div>
                        </div>
                        <div class="layui-form-item layui-form-text">
                            <label for="introduce" class="layui-form-label">签名</label>
                            <div class="layui-input-block">
                                <textarea placeholder="随便写些什么刷下存在感" id="introduce" name="introduce" autocomplete="off"
                                          th:text="${bbsUser.introduce}"
                                          class="layui-textarea" style="height: 80px;"></textarea>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updateInfo()">
                                确认修改
                            </button>
                        </div>
                    </form>
                </div>

                <div class="layui-form layui-form-pane layui-tab-item">
                    <div class="layui-form-item">
                        <div class="avatar-add">
                            <p>建议尺寸168*168,支持jpg、png、gif,最大不能超过1M</p>
                            <button type="button" id="uploadHeadImg" class="layui-btn upload-img">
                                <i class="layui-icon">&#xe67c;</i>上传头像
                            </button>
                            <img id="userHeadImg" th:src="@{${bbsUser.headImgUrl}}">
                            <span class="loading"></span>
                        </div>
                    </div>
                    <div class="layui-form-item">
                        <button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updateHeadImg()">
                            确认修改
                        </button>
                    </div>
                </div>

                <div class="layui-form layui-form-pane layui-tab-item">
                    <form method="post" id="passwordForm" onsubmit="return false;" action="##">
                        <div class="layui-form-item">
                            <label for="originalPassword" class="layui-form-label">当前密码</label>
                            <div class="layui-input-inline">
                                <input type="password" id="originalPassword" name="originalPassword" required
                                       lay-verify="required"
                                       autocomplete="off" class="layui-input">
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label for="newPassword" class="layui-form-label">新密码</label>
                            <div class="layui-input-inline">
                                <input type="password" id="newPassword" name="newPassword" required
                                       lay-verify="required"
                                       autocomplete="off" class="layui-input">
                            </div>
                            <div class="layui-form-mid layui-word-aux">6到20个字符</div>
                        </div>
                        <div class="layui-form-item">
                            <button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updatePassword()">
                                确认修改
                            </button>
                        </div>
                    </form>
                </div>
            </div>

        </div>
    </div>
</div>
</div>

<div class="fly-footer">
    <p>My-BBS社区 2021 &copy; <a href="填写自己的博客" target="_blank">picacho</a></p>
</div>

<script th:src="@{/layui/layui.js}"></script>

</body>
</html>

1.4 测试跳转用户中心功能

访问http://localhost:8080/userSet。由于有拦截器的缘故会跳转到登陆界面,完成登陆后继续访问该路径就可以登陆到set.html界面了。
在这里插入图片描述

2.用户信息修改

用户信息页面中,“我的资料”、“头像”、“密码”三个栏目底部都有一个功能按钮,为“确认修改”。如果想要修改这些信息,也可以对这些用户信息字段进行修改并点击“确认修改”按钮。

这三个功能按钮在点击后都会执行对应的功能,所以在按钮上分别绑定了触发事件,我们需要新增三个 js 方法,分别为 updateInfo() 方法、updateHeadImg() 方法和 updatePassword()方法,作用分别是修改个人信息、修改头像、修改密码。

2.1 修改个人信息

前端页面修改用户信息

updateInfo()方法是修改用户信息,该方法的逻辑如下:

  • 前端对用户输入的数据进行简单的正则验证
  • 封装用户信息实体的参数
  • 向对应的后端修改用户信息接口/updateUserInfo发送 Ajax 请求
  • 请求成功后提醒用户请求成功
  • 请求失败则提醒对应的错误信息

在set.html文件添加js脚本,实现前端的用户信息上传。

<script th:src="@{/js/public.js}"></script>
<script th:src="@{/js/ajaxupload/ajaxupload.js}"></script>
<script type="text/javascript">
    layui.use(['layer', 'element', 'jquery', 'form'], function () {
        var layer = layui.layer, $ = layui.$, element = layui.element, form = layui.form;
        var device = layui.device();
        //阻止IE7以下访问
        if (device.ie && device.ie < 8) {
            layer.alert('如果您非得使用 IE 浏览器访问社区,那么请使用 IE8+');
        }

        //修改个人信息
        window.updateInfo = function () {
            var $ = layui.$;
            var nickName = $("#nickName").val();
            if (!validUserName(nickName)) {
                layer.alert('请输入正确的昵称!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return false;
            }
            var userGender = $('#userGender option:selected').val();
            if (isNull(userGender)) {
                layer.alert('请选择性别!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return;
            }
            var location = $("#location").val();
            if (isNull(location)) {
                layer.alert('请输入所在城市!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return;
            }
            var introduce = $("#introduce").val();
            if (isNull(introduce)) {
                layer.alert('请输入个性签名!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return;
            }
            var params = $("#updateInfoForm").serialize();
            var url = '/updateUserInfo';
            $.ajax({
                type: 'POST',//方法类型
                url: url,
                data: params,
                success: function (result) {
                    if (result.resultCode == 200) {
                        layer.alert('修改成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
                    } else {
                        layer.msg(result.message);
                    }
                    ;
                },
                error: function () {
                    layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                }
            });
        }
    });
</script>

修改个人信息接口
该接口负责接收前端发送的修改用户信息的 POST 请求并处理其中的参数,接收的参数为 nickName 字段、userGender 字段、location 字段和 introduce 字段。接口的映射地址为 /updateUserInfo,请求方法为 POST。

    /**
     * 更新用户基本信息
     * @param nickName
     * @param userGender
     * @param location
     * @param introduce
     * @param httpSession
     * @return
     */
    @PostMapping("/updateUserInfo")
    @ResponseBody
    public Result updateInfo(@RequestParam("nickName") String nickName,
                             @RequestParam("userGender") int userGender,
                             @RequestParam("location") String location,
                             @RequestParam("introduce") String introduce,
                             HttpSession httpSession) {

        if (!StringUtils.hasLength(nickName)) {
            return ResultGenerator.genFailResult("nickName参数错误");
        }
        if (userGender < 1 || userGender > 2) {
            return ResultGenerator.genFailResult("userGender参数错误");
        }
        if (!StringUtils.hasLength(location)) {
            return ResultGenerator.genFailResult("location参数错误");
        }
        if (!StringUtils.hasLength(introduce)) {
            return ResultGenerator.genFailResult("introduce参数错误");
        }
        BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
        bbsUser.setNickName(nickName);
        if (userGender == 1) {
            bbsUser.setGender("男");
        }
        if (userGender == 2) {
            bbsUser.setGender("女");
        }
        bbsUser.setLocation(location);
        bbsUser.setIntroduce(introduce);
        if (bbsUserService.updateUserInfo(bbsUser, httpSession)) {
            Result result = ResultGenerator.genSuccessResult();
            return result;
        } else {
            Result result = ResultGenerator.genFailResult("修改失败");
            return result;
        }
    }

业务层

    @Override
    public Boolean updateUserInfo(BBSUser bbsUser, HttpSession httpSession) {
        BBSUser userTemp = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
        BBSUser userFromDB = bbsUserMapper.selectByPrimaryKey(userTemp.getUserId());
        //当前用户非空且状态正常才可以进行更改
        if (userFromDB != null && userFromDB.getUserStatus().intValue() == 0) {
            userFromDB.setIntroduce(SystemUtil.cleanString(bbsUser.getIntroduce()));
            userFromDB.setLocation(SystemUtil.cleanString(bbsUser.getLocation()));
            userFromDB.setGender(SystemUtil.cleanString(bbsUser.getGender()));
            userFromDB.setNickName(SystemUtil.cleanString(bbsUser.getNickName()));
            if (bbsUserMapper.updateByPrimaryKeySelective(userFromDB) > 0) {
                httpSession.setAttribute(Constants.USER_SESSION_KEY, userFromDB);
                return true;
            }
        }
        return false;
    }

数据持久层

BBSUser selectByPrimaryKey(Long userId);
    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from tb_bbs_user
        where user_id = #{userId,jdbcType=BIGINT}
    </select>

测试效果
在这里插入图片描述
在这里插入图片描述

2.2 修改头像

前端页面修改头像

updateHeadImg()方法是修改用户头像,该方法的逻辑如下:

  • 首先获取用户上传的图片 URL,之后进行简单的正则验证
  • 向对应的后端修改用户头像接口/updateHeadImg发送请求
  • 请求成功后提醒用户修改成功
  • 请求失败则提醒对应的错误信息
       //图片上传插件初始化 用于头像上传
        new AjaxUpload('#uploadHeadImg', {
            action: '/uploadFile',
            name: 'file',
            autoSubmit: true,
            responseType: "json",
            onSubmit: function (file, extension) {
                if (!(extension && /^(jpg|jpeg|png|gif)$/.test(extension.toLowerCase()))) {
                    alert('只支持jpg、png、gif格式的文件!');
                    return false;
                }
            },
            onComplete: function (file, r) {
                if (r != null && r.resultCode == 200) {
                    $("#userHeadImg").attr("src", r.data);
                    return false;
                } else {
                    alert("error");
                }
            }
        });
        //修改头像
        window.updateHeadImg = function () {
            var $ = layui.$;
            var userHeadImg = $('#userHeadImg')[0].src;
            if (isNull(userHeadImg)) {
                layer.alert('头像不能为空字符串!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return false;
            }
            var url = '/updateHeadImg?userHeadImg='+userHeadImg;
            $.ajax({
                type: 'POST',//方法类型
                url: url,
                success: function (result) {
                    if (result.resultCode == 200) {
                        layer.alert('上传成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
                    } else {
                        layer.msg(result.message);
                    }
                    ;
                },
                error: function () {
                    layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                }
            });
        }

修改头像接口
该接口负责接收前端发送的修改用户头像的 POST 请求并处理其中的参数,接收的参数为 userHeadImg 字段,相对来说比较简单,只是修改一个字段而已。

首先需要上传图片然后回显,由UploadController类的方法处理。

	@PostMapping({"/uploadFile"})
    @ResponseBody
    public Result upload(HttpServletRequest httpServletRequest, @RequestParam("file") MultipartFile file) throws URISyntaxException 

之后修改头像,接口的映射地址为 /updateHeadImg,请求方法为 POST。

    /**
     * 修改头像
     * @param userHeadImg
     * @param httpSession
     * @return
     */
    @PostMapping("/updateHeadImg")
    @ResponseBody
    public Result updateHeadImg(@RequestParam("userHeadImg") String userHeadImg,
                                HttpSession httpSession) {

        if (!StringUtils.hasLength(userHeadImg)) {
            return ResultGenerator.genFailResult("userHeadImg参数错误");
        }
        BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
        bbsUser.setHeadImgUrl(userHeadImg);
        if (bbsUserService.updateUserHeadImg(bbsUser, httpSession)) {
            Result result = ResultGenerator.genSuccessResult();
            return result;
        } else {
            Result result = ResultGenerator.genFailResult("修改失败");
            return result;
        }
    }

业务层

    @Override
    public Boolean updateUserHeadImg(BBSUser bbsUser, HttpSession httpSession) {
        BBSUser userFromDB = bbsUserMapper.selectByPrimaryKey(bbsUser.getUserId());
        //当前用户非空且状态正常才可以进行更改
        if (userFromDB != null && userFromDB.getUserStatus().intValue() == 0) {
            userFromDB.setHeadImgUrl(bbsUser.getHeadImgUrl());
            if (bbsUserMapper.updateByPrimaryKeySelective(userFromDB) > 0) {
                httpSession.setAttribute(Constants.USER_SESSION_KEY, userFromDB);
                return true;
            }
        }
        return false;
    }

用户头像修改接口中,首先会对参数进行校验,之后交给业务层代码进行数据封装并进行数据库 update 操作,具体操作步骤如下:

  • 查询用户信息是否存在以及用户状态是否正常
  • 用户信息修改并执行入库操作
  • 重新设置 session 中的用户信息

数据持久层就是前面通过主键查询用户,然后修改字段的方法,这里就不列举了。

测试效果
在这里插入图片描述
在这里插入图片描述

2.3 修改密码

前端页面修改密码

updatePassword()方法是修改密码,该方法的逻辑如下:

  • 前端对用户输入的密码字段进行简单的正则验证和比较
  • 封装密码请求所需的参数
  • 向对应的后端修改用户信息接口/updatePassword发送 Ajax 请求
  • 请求成功后提醒用户修改成功
  • 请求失败则提醒对应的错误信息
        //修改密码
        window.updatePassword = function () {
            var $ = layui.$;
            var originalPassword = $("#originalPassword").val();
            if (!validPassword(originalPassword)) {
                layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return false;
            }
            var newPassword = $("#newPassword").val();
            if (!validPassword(newPassword)) {
                layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return false;
            }
            if (newPassword != newPassword) {
                layer.alert('确认密码与密码字段不相同!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                return false;
            }
            var params = $("#passwordForm").serialize();
            var url = '/updatePassword';
            $.ajax({
                type: 'POST',//方法类型
                url: url,
                data: params,
                success: function (result) {
                    if (result.resultCode == 200) {
                        layer.alert('修改成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
                    } else {
                        layer.msg(result.message);
                    }
                    ;
                },
                error: function () {
                    layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
                }
            });
        }

修改密码接口
该接口负责接收前端发送的修改用户密码的 POST 请求并处理其中的参数,接收的参数为 originalPassword 字段和 newPassword 字段。

接口的映射地址为 /updatePassword,请求方法为 POST。

@PostMapping("/updatePassword")
@ResponseBody
public Result passwordUpdate(HttpServletRequest request, @RequestParam("originalPassword") String originalPassword,
                             @RequestParam("newPassword") String newPassword) {
    if (!StringUtils.hasLength(originalPassword) || !StringUtils.hasLength(newPassword)) {
        return ResultGenerator.genFailResult("参数不能为空");
    }
    BBSUser currentUser = (BBSUser) request.getSession().getAttribute(Constants.USER_SESSION_KEY);
    if (bbsUserService.updatePassword(currentUser.getUserId(), originalPassword, newPassword)) {
        //修改成功后清空session中的数据,前端控制跳转至登录页
        request.getSession().removeAttribute(Constants.USER_SESSION_KEY);
        return ResultGenerator.genSuccessResult();
    } else {
        return ResultGenerator.genFailResult("修改失败");
    }
}

业务层

public Boolean updatePassword(Long userId, String originalPassword, String newPassword) {
    BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(userId);
    //当前用户非空且状态正常才可以进行更改
    if (bbsUser != null && bbsUser.getUserStatus().intValue() == 0) {
        String originalPasswordMd5 = MD5Util.MD5Encode(originalPassword, "UTF-8");
        String newPasswordMd5 = MD5Util.MD5Encode(newPassword, "UTF-8");
        //比较原密码是否正确
        if (originalPasswordMd5.equals(bbsUser.getPasswordMd5())) {
            //设置新密码并修改
            bbsUser.setPasswordMd5(newPasswordMd5);
            if (bbsUserMapper.updateByPrimaryKeySelective(bbsUser) > 0) {
                //修改成功则返回true
                return true;
            }
        }
    }
    return false;
}

首先会对参数进行校验,之后交给业务层代码进行数据封装并进行数据库 update 操作,具体操作步骤如下:

  • 查询用户信息是否存在以及用户状态是否正常
  • 比较原密码 originalPassword 是否与数据库中存储的密码一致,如果不一致不允许修改
  • 重新设置新密码并执行入库操作
  • 由于修改了密码,最后清空了 session 对象中的 user 信息,需要重新登录了

数据持久层就是前面通过主键查询用户,然后修改字段的方法,这里就不列举了。

测试效果
在这里插入图片描述
至此,个人中心设置页面模块就完成了。
项目源码下载地址:源码下载

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
在个人博客系统中,拓展模块是非常重要的,因为它可以提供给用户更多的功能和服务。在本文中,我们将介绍如何在 Spring Boot 项目中实现一个拓展模块。 首先,我们需要先定义一个接口,用于规范拓展模块的实现: ```java public interface BlogModule { String moduleName(); // 获取模块名称 void start(); // 模块启动方法 void stop(); // 模块停止方法 List<String> addPage(String pageName); // 增加页面 } ``` 接下来,我们需要创建一个基础的拓展模块,作为其他拓展模块的基类: ```java public abstract class BaseBlogModule implements BlogModule { private String moduleName; public BaseBlogModule(String moduleName) { this.moduleName = moduleName; } @Override public String moduleName() { return moduleName; } } ``` 在基类中,我们实现了 `moduleName()` 方法,返回拓展模块的名称,并在构造函数中初始化了名称。 然后,我们可以开始实现具体的拓展模块了。假设我们需要实现一个功能,可以在博客系统中添加页面。我们可以创建一个名为 `AddPageModule` 的拓展模块: ```java public class AddPageModule extends BaseBlogModule { private List<String> pages = new ArrayList<>(); public AddPageModule() { super("AddPageModule"); } @Override public void start() { System.out.println("AddPageModule starting..."); } @Override public void stop() { System.out.println("AddPageModule stopping..."); } @Override public List<String> addPage(String pageName) { pages.add(pageName); return pages; } } ``` 在这个拓展模块中,我们实现了 `start()` 和 `stop()` 方法,用于在模块启动和停止时执行一些操作。同时,我们还实现了 `addPage()` 方法,用于添加页面,并返回当前系统中所有的页面。 最后,我们需要在 Spring Boot 项目中将这个拓展模块注入到容器中,并在需要的地方调用它的方法。我们可以使用 `@Autowired` 注解将拓展模块注入到其他组件中: ```java @Service public class BlogService { @Autowired private List<BlogModule> modules; public List<String> addPage(String pageName) { List<String> pages = new ArrayList<>(); for (BlogModule module : modules) { pages.addAll(module.addPage(pageName)); } return pages; } } ``` 在这个示例中,我们使用 `@Autowired` 注解将 `BlogModule` 的实现类自动注入到 `modules` 列表中,并在 `addPage()` 方法中循环遍历所有的模块,调用它们的 `addPage()` 方法。 通过这种方式,我们可以轻松地实现一个可拓展的 Spring Boot 项目,并在需要的时候动态地增加或删除拓展模块

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picacho_pkq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值