首页
碎碎念
技术分享
开发日志
学习日记
追剧
番
电视剧
电影
闲言碎语
精美壁纸
留言板
个人导航
关于我
归档
用户登录
用户名
密码
登录
注册
关键词搜索
搜索
标签搜索
java
追番~~
计网
c#
unity
脆皮大学生
spring AOP
博客更新
selenium
web测试
springboot
ES6
vue3
elementPlus
idea
近期浏览
热门文章
1
动漫分享---《想要成为影之实力者》
1.4k 阅读
2
在unity中使用c#语言实现人物的转身
1.4k 阅读
3
可恶的日本军国主义!我们一定不能遗忘这段历史,遗忘历史就意味着背叛!!!!
1.3k 阅读
4
Java与Selenium自动化测试全面指南
1.3k 阅读
5
Unity冲刺机制:如何实现角色冲刺
1.3k 阅读
6
SpringMVC 入门教程(基于Java配置类)
1.3k 阅读
7
子网划分与CIDR
1.2k 阅读
8
我的第一个blog
1.2k 阅读
9
分享键盘
1.1k 阅读
Charlotte
累计撰写
54
篇文章
累计添加
17
个标签
累计收到
50
条评论
首页
分类
碎碎念
技术分享
开发日志
学习日记
追剧
番
电视剧
电影
页面
闲言碎语
精美壁纸
留言板
个人导航
关于我
归档
用户登录
登录
注册
“技术分享” 共(27)篇
Spring Cloud Alibaba 版本适配脚手架
在写Spring Cloud的项目的时候,各种依赖的版本问题总是会让人头疼,那么可以借助阿里的脚手架来进行版本适配,网址如下:阿里 云原生应用脚手架 :https://start.aliyun.com/选择完后点击浏览代码可以浏览pom文件,查看依赖的版本
5个月前
366
0
1
Docker安装Nacos
Nacos是一个展示一系列管理主要服务的应用、控制和分发的主要工具。本文将指导您如何使用Docker安装Nacos服务器。步骤指南搜索库中是否有nacos镜像可以使用。docker search nacos从Docker Hub中拉取最新版本的Nacos镜像。docker pull nacos/nacos-server镜像拉完后,使用下面的命令启动Nacos服务器,此处使用的是单机模式。docker run -d \ --name nacos \ --privileged \ --cgroupns host \ --env JVM_XMX=256m \ --env MODE=standalone \ --env JVM_XMS=256m \ -p 8848:8848/tcp \ -p 9848:9848/tcp \ --restart=always \ -w /home/nacos \ nacos/nacos-server上述命令解释:--name nacos: 指定开启的容器名称为 nacos--privileged: 使用特权模式启动容器--cgroupns host: 指定 cgroup 的认识级别运行方式--env JVM_XMX=256m 和 --env JVM_XMS=256m: 设置 JVM 的最大内存和初始内存为 256MB--env MODE=standalone: 代表单机模式-p 8848:8848/tcp 和 -p 9848:9848/tcp: 是映射渠口 8848 和 9848--restart=always: 设置当 Docker 重启后还可以自动启动容器-w /home/nacos: 设置工作目录为 /home/nacos使用渠口连接到 Nacos 服务器。在云服务器上启动后,不要忘记打开云服务器的符合渠口和防火墙配置。连接到 Nacos 控制台方式如下:在浏览器输入 ip地址:8848/nacos 即可进入Nacos控制台。Nacos 相关资料Nacos的文档Nacos 的架构原理
5个月前
190
0
0
Docker 安装 Jenkins 实现自动打包部署
Jenkins 是一个用来实现自动化部署的工具,在应用开发中非常有用。本文将详细记录如何通过 Docker 安装 Jenkins 的过程。前置条件在开始前,需要确保你的机器上已经安装了 JDK。可以通过以下命令来安装 OpenJDK 1.8 版本:yum install -y java-1.8.0-openjdk.x86_64确认 JDK 已成功安装后,我们就可以开始安装 Jenkins。在 Docker 上安装 Jenkins1. 查找 Jenkins 镜像首先,查询 Docker 中有哪些可用的 Jenkins 镜像:docker search jenkins2. 拉取 Jenkins 镜像从 Docker Hub 中拉取 Jenkins 的指定版本镜像,这里我们选择 2.414.2 版本:docker pull jenkins/jenkins:2.414.23. 运行 Jenkins 容器运行 Jenkins 并设置一些基本参数:docker run -d -u root -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins/jenkins:2.414.2-d:以后台模式运行容器。-u root:以 root 用户运行 Jenkins,方便访问系统文件。-p 8080:8080:将容器的 8080 端口映射到主机的 8080 端口,用于连接 Jenkins。-p 50000:50000:用于 Jenkins agent 的连接。-v /var/jenkins_home:/var/jenkins_home:挂载数据卷以持久化 Jenkins 的数据。4. 启动 Jenkins启动 Jenkins 容器:docker start jenkins查看docker正在运行的容器:docker ps -a此时 Jenkins 已经启动完成,可以通过浏览器访问 http://<服务器IP>:8080 来连接 Jenkins。首次访问可能需要一些时间来等待启动过程完成。建议使用内存较大的服务器,因为内存不足的云服务器可能会导致 Jenkins 启动失败。获取 Jenkins 初始密码启动完成后,可以通过查看 Jenkins 容器的日志来获取初始密码:docker logs jenkins然后,在访问 Jenkins("<服务器IP>:8080")时,在页面上输入获取到的初始密码即可。在此步骤中,可以选择安装方式,推荐安装默认插件以获得最佳体验在这个界面等待安装完成安装完成后会需要创建一个管理员账户,创建完后点击保存并完成完成管理员账户的创建后,点击保存并继续以完成配置过程大功告成!然后点击新建item输入任务名称,选择Freestyle project配置源码管理,选择git,填写项目地址并添加凭证由于github已经取消使用账号和密码的方式来连接仓库,否则会拒绝访问,所以这里配置使用ssh密钥的方式。{collapse}{collapse-item label="配置凭证步骤" open}下面是通过 SSH 私钥和公钥配置 Jenkins 凭证的完整过程:在 Jenkins 中配置 SSH 凭证要配置 Jenkins 与 Git 之间的凭证连接,我们可以通过生成并使用 SSH 私钥和公钥来实现。这是一个安全且常见的做法,确保 Jenkins 能够访问你的代码库。以下是配置的完整步骤。1. 生成 SSH 密钥对首先,我们需要在服务器上生成 SSH 密钥对,用于 Jenkins 连接 Git 代码库。请使用以下命令生成 SSH 密钥对:ssh-keygen -t rsa -b 4096 -C "jenkins@example.com"-t rsa:指定密钥类型为 RSA。-b 4096:密钥长度为 4096 位。-C "jenkins@example.com":为密钥加上注释,以便识别。在命令执行后,系统会询问你密钥的存储位置,默认位置一般为 ~/.ssh/id_rsa。你也可以为其指定一个新的存储路径。2. 查看生成的公钥生成密钥对后,接下来要获取公钥内容,以便添加到代码库的版本控制系统中,确保 Jenkins 能够克隆代码。执行以下命令查看公钥:cat ~/.ssh/id_rsa.pub将输出的公钥内容复制下来,然后登录到你代码仓库的控制台(例如 GitHub、GitLab 或 Bitbucket),将公钥添加到仓库的 Deploy keys 或 SSH keys 选项中,授予 Jenkins 对仓库的读权限。3. 将私钥添加到 Jenkins 凭证中现在,我们需要将私钥配置到 Jenkins 中,确保 Jenkins 在运行构建任务时能够使用 SSH 凭证访问代码仓库。在 Kind(类型)下拉菜单中选择 SSH Username with private key(带私钥的 SSH 用户名)。Username:输入一个名称,例如 jenkins。Private Key(私钥):选择 Enter directly(直接输入),然后将之前生成的 SSH 私钥内容粘贴到这里。可以使用以下命令查看私钥内容:cat ~/.ssh/id_rsa将输出的内容复制粘贴到 Jenkins 的 Private Key 文本框中。Passphrase(密码):如果在生成密钥时设置了密码,这里需要填写;如果没有设置,可以留空。最后,点击 OK 保存凭证。{/collapse-item}{/collapse}配置jenkins的maven版本为了在Jenkins上运行Maven构建任务,我们需要在系统上安装Maven。1 下载并解压Maven前往 Maven官网 下载所需版本的Maven压缩包,或者直接使用命令下载并解压:# 下载 Maven (以版本3.8.8为例) wget https://downloads.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz # 解压并移动到 /opt 目录 sudo tar -zxvf apache-maven-3.8.8-bin.tar.gz -C /opt2 配置环境变量接下来配置Maven的环境变量,以便系统中的所有用户都可以访问Maven:# 编辑 /etc/profile 文件 sudo vi /etc/profile在文件末尾添加以下内容:export M2_HOME=/opt/apache-maven-3.8.8 export PATH=$M2_HOME/bin:$PATH然后加载环境变量:source /etc/profile验证Maven是否安装成功:mvn -v3. 在Jenkins中配置Maven3.1 登录Jenkins在浏览器中访问Jenkins的地址,通常是 http://<服务器IP>:8080,登录到Jenkins管理界面。3.2 安装Maven Integration插件为了在Jenkins中使用Maven,我们需要安装Maven Integration插件:点击 "Manage Jenkins" (管理Jenkins)。点击 "Manage Plugins" (管理插件)。选择 "Available" (可用) 选项卡。搜索 "Maven Integration",然后安装该插件。3.3 配置Maven在Jenkins主界面,点击 "Manage Jenkins"。点击 "Global Tool Configuration" (全局工具配置)。滑动到 "Maven" 部分,点击 "Add Maven" (添加Maven)。给Maven设置一个名称,例如 "Maven 3.8.8"。取消选择 "Install automatically" (自动安装),并在 "MAVEN_HOME" 中填写之前Maven的安装路径,例如:/opt/apache-maven-3.8.8保存设置。4. 配置Jenkins任务使用Maven在为某个项目配置构建任务时,可以选择使用Maven:新建一个 "Freestyle project"。在构建部分,选择 "Invoke top-level Maven targets"。在 "Maven Version" 下拉框中选择之前配置的Maven版本 (例如 "Maven 3.8.8")。在 "Goals" 中填写需要执行的Maven命令,例如 clean install。5. 验证配置保存任务配置后,点击 "Build Now" (立即构建),观察构建日志,确认Maven已经正确执行。6. 可能遇到的问题6.1 环境变量未生效如果Maven未能成功运行,可能是环境变量没有正确加载,建议重新加载环境变量或重启Jenkins:# 重启Jenkins sudo systemctl restart jenkins6.2 权限问题确保Jenkins用户对Maven的安装目录有读执行权限,可以通过以下命令修改权限:sudo chmod -R 755 /opt/apache-maven-3.8.8在Jenkins中配置部署时,我使用了“Send files or execute commands over SSH”插件来自动化应用程序的部署。以下是我配置的脚本详细步骤和说明,脚本主要用于停止正在运行的Java应用并重新启动新版本。配置过程首先,我在Jenkins中使用了 Send files or execute commands over SSH 来执行脚本,通过SSH命令将构建生成的文件拷贝到服务器指定路径,并进行应用的停止和启动操作。文件复制部分cp /var/jenkins_home/workspace/jc-club-subject/jc-club-subject/jc-club-starter/target/jc-club-starter.jar /var/jenkins_home/jar/这条命令的作用是将构建好的 jc-club-starter.jar 文件从Jenkins的工作空间复制到目标目录 /var/jenkins_home/jar/ 中,以便后续进行启动操作。脚本内容下面的脚本用于停止正在运行的应用并重新启动新的版本:#!/bin/bash APP_NAME=jc-club-starter.jar LOG_NAME=jc-club-starter.log pid=`ps -ef | grep $APP_NAME | grep -v grep|awk '{print $2}'` function is_exist(){ pid=`ps -ef | grep $APP_NAME | grep -v grep|awk '{print $2}'` if [ -z ${pid} ]; then String="notExist" echo $String else String="exist" echo $String fi } str=$(is_exist) if [ ${str} = "exist" ]; then echo " 检测到已经启动的程序,pid 是 ${pid} " kill -9 $pid else echo " 程序没有启动了 " echo "${APP_NAME} is not running" fi str=$(is_exist) if [ ${str} = "exist" ]; then echo "${APP_NAME} 已经启动了. pid=${pid} ." else source /etc/profile BUILD_ID=dontKillMe nohup java -Xms300m -Xmx300m -jar /var/jenkins_home/jar/$APP_NAME >$LOG_NAME 2>&1 & echo "程序已重新启动..." fi脚本解析定义变量APP_NAME=jc-club-starter.jar:指定要启动的Java应用程序的名称。LOG_NAME=jc-club-starter.log:指定日志文件名称。检查应用是否存在通过 is_exist 函数来检测应用是否正在运行。使用 ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}' 来获取应用的进程ID(PID)。如果没有找到PID,则表示应用没有运行。停止正在运行的应用调用 is_exist 函数,如果返回 exist,说明程序正在运行,则使用 kill -9 $pid 强行停止该进程。如果程序未启动,则打印信息提示。重新启动应用再次调用 is_exist 函数来确认应用是否已被停止。如果程序未运行,使用 nohup 命令重新启动应用。source /etc/profile:加载环境变量。BUILD_ID=dontKillMe:防止Jenkins自动杀死后台运行的进程。nohup java -Xms300m -Xmx300m -jar /var/jenkins_home/jar/$APP_NAME >$LOG_NAME 2>&1 &:以 nohup 方式启动应用,并将日志输出到指定的日志文件中。
5个月前
208
0
1
解决 Docker 安装镜像时的网络超时问题
在使用 Docker 搜索并安装镜像时,可能会遇到网络超时的问题,例如在执行以下命令时:docker search jenkins报错信息如下:Error response from daemon: Get "https://index.docker.io/v1/search?q=jenkins&n=25": dial tcp 31.13.87.34:443: i/o timeout这种情况通常是由于 Docker 默认源网络不稳定导致的。解决方法就是更换 Docker 镜像源。本文将为您介绍如何通过更换镜像源解决此类问题。最基础的解决方法:修改 /etc/docker/daemon.json 文件该文件用于配置 Docker 参数,默认是不存在的,需要自己创建。首先使用 cat 命令查看一下 daemon.json 中有没有内容:cat /etc/docker/daemon.json如果没有内容或者此文件不存在,我们可以使用 touch 命令创建并命名为 daemon.json 文件:touch /etc/docker/daemon.json通过 vim 命令打开 daemon.json 文件,注意如果您已经切换到 /etc/docker 目录中,可以直接使用 vim 进入即可:vi /etc/docker/daemon.json点击键盘上的 i 键切换到插入模式,在插入模式中将以下内容复制粘贴:{ "registry-mirrors": [ "https://registry.docker-cn.com", "http://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn", "https://pee6w651.mirror.aliyuncs.com" ] }点击键盘 Esc 键退出插入模式,点击键盘 Shift + :,在冒号后面输入 wq 进行保存并退出。重启 Docker 使更改生效:systemctl daemon-reload systemctl restart docker目前可用的镜像代理拉取 pull 镜像时,遇到不可用、关停、访问比较慢的状态,建议同时配置多个镜像源。提供商地址DaoCloudhttps://docker.m.daocloud.io阿里云https://<your_code>.mirror.aliyuncs.comDocker镜像代理https://dockerproxy.com百度云https://mirror.baidubce.com南京大学https://docker.nju.edu.cn中科院https://mirror.iscas.ac.cn解决方案1:配置加速地址配置加速地址适用于 Ubuntu 16.04+、Debian 8+、CentOS 7+。具体步骤如下:方式一:配置 daemon.json 文件创建或编辑 /etc/docker/daemon.json 文件:sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://do.nark.eu.org", "https://dc.j8.work", "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.mirrors.ustc.edu.cn", "https://docker.nju.edu.cn" ] } EOF重启 Docker 使更改生效:sudo systemctl daemon-reload sudo systemctl restart docker检查加速是否生效:docker info如果从输出结果中看到了配置的 registry-mirrors 地址,说明配置成功。方式二:直接使用镜像加速地址如果有正在运行的容器不方便重启 Docker 服务,可以直接在拉取镜像时使用加速地址,例如:docker pull do.nark.eu.org/library/mysql:5.7第三方镜像AtomHub 可信镜像中心:大部分需要的镜像都可以找到。官网:https://atomhub.openatom.cn/用法示例:docker pull atomhub.openatom.cn/amd64/redis:7.0.13在使用 docker compose 时,可以先拉取对应版本的镜像,然后再执行 docker compose。加速代理站点Github 下载加速代理站点:站点地址:https://docker.888666222.xyz/设置方法:sudo tee /etc/docker/daemon.json <<EOF { "registry-mirrors": ["https://docker.888666222.xyz"] } EOF拉取镜像并重新打标签:docker pull docker.888666222.xyz/library/alpine:latest docker pull docker.888666222.xyz/coredns/coredns:latest解决方案2:使用代理拉取镜像创建配置文件:sudo mkdir -p /etc/systemd/system/docker.service.d sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf在文件中添加代理设置:[Service] Environment="HTTP_PROXY=socks5://user:pass@127.0.0.1:1080" Environment="HTTPS_PROXY=socks5://user:pass@127.0.0.1:1080"重启 Docker:sudo systemctl daemon-reload sudo systemctl restart docker查看环境变量:sudo systemctl show --property=Environment docker解决方案3:直接传送镜像A 服务器保存 Docker 镜像:docker save myimage > myimage.tar将镜像传送到 B 服务器:scp myimage.tar root@192.0.2.0:/homeB 服务器加载 Docker 镜像:cd /home docker load < myimage.tar查看镜像:docker images
5个月前
436
0
1
MyBatis-Plus SQL 日志输出配置和自定义 SQL 拦截器实现
在项目中进行 SQL 调试时,输出详细的 SQL 日志是很有帮助的,特别是在 SQL 性能分析和优化方面。下面我们通过配置 MyBatis-Plus 的日志输出以及自定义 SQL 拦截器,实现 SQL 日志的详细输出。一、MyBatis-Plus 的日志配置首先,我们在 application.yml 文件中配置 MyBatis-Plus 的日志实现类,使用标准输出日志实现:# MyBatis-Plus配置 mybatis-plus: # 配置日志实现类 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这个配置将会在控制台输出 SQL 执行的日志,便于我们调试和查看 SQL 语句。二、创建自定义 SQL 拦截器为了输出更加详细的 SQL 日志,我们可以通过自定义拦截器来记录 SQL 的执行时间和具体的 SQL 语句。这里我们实现了两个配置类,SqlStatementInterceptor 和 MybatisPlusAllSqlLog,用于拦截 SQL 操作并输出相关日志信息。先取消上述在application的日志配置!!!!!!!1. SqlStatementInterceptor 拦截器这个拦截器主要用于记录每条 SQL 的执行时间,并对执行超过特定阈值的 SQL 进行额外的日志输出,便于分析慢查询。package com.jingdianjichi.subject.infra.config; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Properties; @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}) }) public class SqlStatementInterceptor implements Interceptor { public static final Logger log = LoggerFactory.getLogger("sys-sql"); @Override public Object intercept(Invocation invocation) throws Throwable { long startTime = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long timeConsuming = System.currentTimeMillis() - startTime; log.info("执行SQL:{}ms", timeConsuming); if (timeConsuming > 999 && timeConsuming < 5000) { log.info("执行SQL大于1s:{}ms", timeConsuming); } else if (timeConsuming >= 5000 && timeConsuming < 10000) { log.info("执行SQL大于5s:{}ms", timeConsuming); } else if (timeConsuming >= 10000) { log.info("执行SQL大于10s:{}ms", timeConsuming); } } } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 可添加自定义属性 } }该拦截器拦截了 MyBatis 的 query 和 update 方法,记录 SQL 的执行时间,并针对不同的时间区间输出相应的日志。2. MybatisPlusAllSqlLog 拦截器这个拦截器的作用是获取完整的 SQL 语句并将其打印出来。MyBatis 的 SQL 通常会带有占位符(?),该拦截器会将占位符替换为实际参数,输出完整的可执行 SQL 语句。package com.jingdianjichi.subject.infra.config; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.type.TypeHandlerRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import java.sql.SQLException; import java.text.DateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; public class MybatisPlusAllSqlLog implements InnerInterceptor { public static final Logger log = LoggerFactory.getLogger("sys-sql"); @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { logInfo(boundSql, ms, parameter); } @Override public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); logInfo(boundSql, ms, parameter); } private static void logInfo(BoundSql boundSql, MappedStatement ms, Object parameter) { try { log.info("parameter = " + parameter); String sqlId = ms.getId(); log.info("sqlId = " + sqlId); Configuration configuration = ms.getConfiguration(); String sql = getSql(configuration, boundSql, sqlId); log.info("完整的sql:{}", sql); } catch (Exception e) { log.error("异常:{}", e.getLocalizedMessage(), e); } } public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) { return sqlId + ":" + showSql(configuration, boundSql); } public static String showSql(Configuration configuration, BoundSql boundSql) { Object parameterObject = boundSql.getParameterObject(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); if (!CollectionUtils.isEmpty(parameterMappings) && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject))); } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty(); if (metaObject.hasGetter(propertyName)) { Object obj = metaObject.getValue(propertyName); sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj))); } else if (boundSql.hasAdditionalParameter(propertyName)) { Object obj = boundSql.getAdditionalParameter(propertyName); sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj))); } else { sql = sql.replaceFirst("\\?", "缺失"); } } } } return sql; } private static String getParameterValue(Object obj) { String value; if (obj instanceof String) { value = "'" + obj.toString() + "'"; } else if (obj instanceof Date) { DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA); value = "'" + formatter.format(new Date()) + "'"; } else { value = (obj != null) ? obj.toString() : ""; } return value; } }3. MybatisConfiguration 配置类最后再创建一个MybatisConfiguration配置类,通过配置 MybatisPlusInterceptor 实现了对 SQL 日志的拦截和输出,并将自定义的 MybatisPlusAllSqlLog 拦截器添加到了 MyBatis 拦截器链中。package com.jingdianjichi.subject.infra.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisConfiguration { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new MybatisPlusAllSqlLog()); return mybatisPlusInterceptor; } }最后发送请求,得出如下图的日志效果
5个月前
260
0
0
Spring Boot 中定制 ObjectMapper 的全局 JSON 序列化配置
在开发 Web API 时,处理 JSON 数据的序列化和反序列化是非常常见的需求。Spring Boot 默认使用 Jackson 来进行 JSON 的处理,但有时候我们需要对 Jackson 的 ObjectMapper 进行自定义配置,以满足特定的业务需求。1. 全局配置 ObjectMapper在 Spring Boot 中,我们可以通过自定义 HttpMessageConverter 来实现全局的 JSON 序列化配置。具体实现如下:package com.jingdianjichi.subject.application.config; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Configuration public class GlobalConfig extends WebMvcConfigurationSupport { @Override protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(mappingJackson2HttpMessageConverter()); } private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { ObjectMapper objectMapper = new ObjectMapper(); // 1. 允许空对象序列化 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // 2. 忽略空值字段 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return new MappingJackson2HttpMessageConverter(objectMapper); } }在这个类中,我们继承了 WebMvcConfigurationSupport 并覆盖了 configureMessageConverters 方法,通过添加自定义的 MappingJackson2HttpMessageConverter 实现了对全局 JSON 处理的自定义。2. 配置详解接下来,我们详细解读两行关键代码,它们分别实现了忽略空字段和允许空对象序列化的功能。2.1 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);这行代码的作用是控制 Jackson 是否允许序列化空对象。SerializationFeature.FAIL_ON_EMPTY_BEANS: 默认情况下,Jackson 在遇到没有任何字段的空对象时会抛出异常。例如,当你有一个类的所有字段值都为 null 或没有任何字段时,Jackson 会认为这个对象无法序列化,并抛出错误。false: 通过将这个配置项设置为 false,即使对象为空,Jackson 仍然会将其序列化为 {},而不会抛出异常。这对于一些复杂对象结构或需要返回空对象的场景非常有用。示例:如果我们有一个类 User,但所有字段都是空的,默认情况下序列化会失败,而通过这行配置后,可以安全地将其序列化为 {}。2.2 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);这行代码用于设置对象序列化时的字段包含规则,具体是忽略 null 值的字段。JsonInclude.Include.NON_NULL: 该配置告诉 Jackson 在序列化时,忽略所有值为 null 的字段。也就是说,如果对象的某个字段值为 null,那么这个字段不会出现在最终的 JSON 结果中。示例:假设我们有如下 Java 对象:User user = new User(); user.setName(null); user.setAge(25);通过配置 NON_NULL,序列化后的 JSON 将会是:{ "age": 25 }而不会包含 null 值的 name 字段。这样可以减少 API 响应的大小,同时提高数据的简洁性。
5个月前
177
0
1
SpringBoot基于工厂+策略模式的题目处理思路详解
在软件开发中,常常会遇到需要根据不同类型执行不同处理逻辑的场景。如果直接使用大量的 if-else 或 switch-case,代码会变得冗长且难以维护。为了解决这个问题,我们可以采用策略模式和工厂模式,使代码结构更加清晰,且方便扩展。下面,我将结合代码,详细讲解这种设计思路,并说明实现后数据的流向。特别是,对于工厂类的设计,我们将进行详细的拆分和讲解。一、设计思路1. 问题背景有一个试题需求,需要处理多种类型的题目:单选题(RADIO)多选题(MULTIPLE)判断题(JUDGE)简答题(BRIEF)每种题型的处理逻辑不同,如果直接在代码中大量使用条件判断,不利于代码的维护和扩展。2. 设计目标解耦不同题型的处理逻辑:每种题型的处理逻辑独立,互不影响。提高代码的可扩展性:新增题型时,尽量不修改原有代码。简化业务层的代码:业务层不需要关注具体的处理逻辑。3. 采用的设计模式策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,使它们可以互相替换,且算法的变化不会影响到使用算法的客户。工厂模式(Factory Pattern):定义一个创建对象的接口,让子类决定实例化哪个类。4. 设计步骤定义策略接口:抽象出题目处理的通用接口。实现具体策略类:为每种题型创建一个处理器,实现策略接口。创建工厂类:根据题目类型,返回对应的处理器。业务层使用工厂获取处理器:业务层调用处理器的方法,完成题目的处理。二、代码实现1. 定义策略接口 SubjectTypeHandlerpublic interface SubjectTypeHandler { SubjectInfoTypeEnum getHandlerType(); void add(SubjectInfoBO subjectInfoBO); }getHandlerType():返回处理器对应的题目类型枚举。add(SubjectInfoBO subjectInfoBO):处理添加题目的方法。2. 实现具体策略类(1)单选题处理器 RadioTypeHandlerpublic class RadioTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.RADIO; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现单选题的添加逻辑 System.out.println("添加单选题:" + subjectInfoBO); } }(2)多选题处理器 MultipleTypeHandlerpublic class MultipleTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.MULTIPLE; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现多选题的添加逻辑 System.out.println("添加多选题:" + subjectInfoBO); } }(3)判断题处理器 JudgeTypeHandlerpublic class JudgeTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.JUDGE; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现判断题的添加逻辑 System.out.println("添加判断题:" + subjectInfoBO); } }(4)简答题处理器 BriefTypeHandlerpublic class BriefTypeHandler implements SubjectTypeHandler { @Override public SubjectInfoTypeEnum getHandlerType() { return SubjectInfoTypeEnum.BRIEF; } @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现简答题的添加逻辑 System.out.println("添加简答题:" + subjectInfoBO); } }3. 创建工厂类 SubjectTypeHandlerFactory下面,我们对工厂类的设计进行详细的拆分和讲解。(1)工厂类的定义@Component public class SubjectTypeHandlerFactory implements InitializingBean { // 注入所有实现了 SubjectTypeHandler 接口的处理器 @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>(); public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); } @Override public void afterPropertiesSet() { // 将处理器按题目类型存入 Map for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } } }一定要注意添加@Component注解,表示将代码交给springboot托管,否则代码不会生效,这样在springboot在启动完成之后,我们的Handler就被装配进了spring容器了。(2)成员变量和注入// 注入所有实现了 SubjectTypeHandler 接口的处理器 @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();subjectTypeHandlerList:通过 @Resource 注解,Spring 会自动注入容器中所有实现了 SubjectTypeHandler 接口的 Bean。handlerMap:用于存储题目类型与对应处理器的映射关系。(3)初始化方法 afterPropertiesSet()@Override public void afterPropertiesSet() { // 将处理器按题目类型存入 Map for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } }作用:在 Bean 初始化完成后,Spring 会调用 afterPropertiesSet() 方法。逻辑:遍历 subjectTypeHandlerList,获取每个处理器。调用处理器的 getHandlerType() 方法,获取对应的题目类型。将题目类型和处理器存入 handlerMap,建立映射关系。目的:将所有的处理器按照题目类型注册到工厂中,方便后续根据题目类型获取对应的处理器。(4)获取处理器方法 getHandler(int subjectType)public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }参数:subjectType,题目类型的整数表示。逻辑:调用 SubjectInfoTypeEnum.getByCode(subjectType),将整数类型转换为对应的枚举类型 SubjectInfoTypeEnum。从 handlerMap 中获取对应的处理器。返回值:SubjectTypeHandler,对应题目类型的处理器。(5)类注解 @Component@Component public class SubjectTypeHandlerFactory implements InitializingBean { ... }@Component:将工厂类声明为一个 Spring Bean,交由 Spring 容器管理。implements InitializingBean:实现 InitializingBean 接口,目的是在 Bean 初始化后执行 afterPropertiesSet() 方法。4. 业务层调用@Service public class SubjectService { @Autowired private SubjectTypeHandlerFactory handlerFactory; public void addSubject(SubjectInfoBO subjectInfoBO) { // 获取对应的处理器 SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType()); if (handler != null) { // 调用处理器的添加方法 handler.add(subjectInfoBO); } else { throw new IllegalArgumentException("未知的题目类型"); } } }注入工厂类:@Autowired 将 SubjectTypeHandlerFactory 注入到业务层。添加题目方法:根据 subjectInfoBO.getType() 获取题目类型。调用工厂的 getHandler() 方法获取对应的处理器。调用处理器的 add() 方法,处理题目添加逻辑。三、实现后的数据流向1. 数据流整体概述当需要添加一个新题目时,数据流向如下:接收请求:SubjectService.addSubject() 接收 SubjectInfoBO 对象,包含题目的详细信息。获取处理器:SubjectTypeHandlerFactory.getHandler() 根据题目类型返回对应的处理器。处理题目:调用处理器的 add() 方法,执行具体的处理逻辑。完成添加:处理器完成题目的添加操作。2. 数据流详细步骤(1)接收题目信息SubjectInfoBO subjectInfoBO = new SubjectInfoBO(); subjectInfoBO.setType(1); // 假设 1 代表单选题 subjectInfoBO.setContent("题目内容"); // ... 设置其他属性 subjectService.addSubject(subjectInfoBO);创建题目对象:实例化 SubjectInfoBO,设置题目类型和内容等属性。调用业务方法:调用 SubjectService.addSubject() 方法,传入题目对象。(2)业务层获取处理器public void addSubject(SubjectInfoBO subjectInfoBO) { // 获取处理器 SubjectTypeHandler handler = handlerFactory.getHandler(subjectInfoBO.getType()); // ... }获取题目类型:从 subjectInfoBO 中获取题目类型。调用工厂方法:使用工厂的 getHandler() 方法获取对应的处理器。(3)工厂返回处理器public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }类型转换:将整数类型的题目类型转换为枚举类型。获取处理器:从 handlerMap 中根据枚举类型获取处理器。(4)处理器处理题目if (handler != null) { handler.add(subjectInfoBO); } else { throw new IllegalArgumentException("未知的题目类型"); }调用处理方法:如果获取到了处理器,调用其 add() 方法。异常处理:如果没有对应的处理器,抛出异常。处理器的 add() 方法,例如单选题处理器:public class RadioTypeHandler implements SubjectTypeHandler { @Override public void add(SubjectInfoBO subjectInfoBO) { // 实现单选题的添加逻辑 System.out.println("添加单选题:" + subjectInfoBO); // 例如,将题目信息保存到数据库 } }具体处理逻辑:处理器执行特定题型的添加逻辑,例如数据校验、数据库操作等。3. 数据流示意图用户请求 --> SubjectService.addSubject() --> SubjectTypeHandlerFactory.getHandler() --> 返回对应处理器 | v 调用处理器的 add() 方法 --> 处理器执行添加逻辑 --> 完成题目添加四、工厂类设计的详细讲解1. 工厂类的职责SubjectTypeHandlerFactory 的主要职责是根据题目类型返回对应的处理器。这一过程包含:初始化处理器映射关系:在工厂类初始化时,将所有的处理器注册到一个映射中。提供获取处理器的方法:根据题目类型,返回相应的处理器实例。2. 工厂类的实现细节(1)注入所有处理器@Resource private List<SubjectTypeHandler> subjectTypeHandlerList;@Resource 注解:由 Spring 自动注入容器中所有实现了 SubjectTypeHandler 接口的 Bean。目的:获取所有的处理器实例,方便后续的映射注册。(2)定义处理器映射private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();handlerMap:用于存储题目类型和处理器实例的对应关系。类型安全:使用 SubjectInfoTypeEnum 作为键,确保类型的一致性。(3)初始化处理器映射@Override public void afterPropertiesSet() { for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } }afterPropertiesSet() 方法:由 InitializingBean 接口提供,在 Bean 的属性设置完成后由 Spring 自动调用。处理逻辑:遍历 subjectTypeHandlerList 中的所有处理器。调用每个处理器的 getHandlerType() 方法,获取其支持的题目类型。将题目类型和处理器实例存入 handlerMap。(4)获取处理器的方法public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); return handlerMap.get(typeEnum); }参数说明:subjectType,题目类型的整数表示。步骤解析:类型转换:调用 SubjectInfoTypeEnum.getByCode(subjectType) 方法,将整数类型转换为枚举类型。SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType);获取处理器:从 handlerMap 中根据枚举类型获取对应的处理器实例。return handlerMap.get(typeEnum);返回值:对应题目类型的处理器,如果不存在则返回 null。(5)异常处理(可选)在实际应用中,可能需要对获取不到处理器的情况进行处理,可以在 getHandler() 方法中添加异常处理:public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); SubjectTypeHandler handler = handlerMap.get(typeEnum); if (handler == null) { throw new IllegalArgumentException("未知的题目类型:" + subjectType); } return handler; }目的:避免业务层需要处理 null 值,将异常抛出,提高代码的健壮性。(6)工厂类的优势集中管理:所有处理器的实例化和获取都由工厂类负责,方便管理。解耦业务层和处理器:业务层无需关心处理器的实现细节,只需通过工厂获取即可。易于扩展:新增题型处理器时,只需实现 SubjectTypeHandler 接口,并将其注册到 Spring 容器中,无需修改工厂类的代码。3. 工厂类的完整代码@Component public class SubjectTypeHandlerFactory implements InitializingBean { @Resource private List<SubjectTypeHandler> subjectTypeHandlerList; private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>(); public SubjectTypeHandler getHandler(int subjectType) { SubjectInfoTypeEnum typeEnum = SubjectInfoTypeEnum.getByCode(subjectType); SubjectTypeHandler handler = handlerMap.get(typeEnum); if (handler == null) { throw new IllegalArgumentException("未知的题目类型:" + subjectType); } return handler; } @Override public void afterPropertiesSet() { for (SubjectTypeHandler handler : subjectTypeHandlerList) { handlerMap.put(handler.getHandlerType(), handler); } } }
5个月前
179
0
0
idea使用EasyCode插件快速生成代码
快速提升开发效率:在 IntelliJ IDEA 中使用 EasyCode 插件自动生成代码什么是 EasyCode 插件EasyCode 是一款专为 IntelliJ IDEA 设计的代码生成插件。它能够根据数据库表结构,自动生成包括实体类、DAO、Service、Controller 等在内的多层代码,大幅减少开发者的重复劳动。同时,EasyCode 支持自定义模板,允许开发者根据项目需求定制代码生成规则,极大地提高了代码的一致性和可维护性。EasyCode 的主要功能EasyCode 提供了丰富的功能,帮助开发者快速生成各种层次的代码。其主要功能包括:自动生成实体类:根据数据库表结构生成 Java 实体类,支持 Lombok 注解,简化代码编写。生成 DAO 层代码:自动生成 MyBatis 或其他 ORM 框架的 Mapper 接口和 XML 配置文件。生成 Service 和 Controller 层代码:快速生成业务逻辑层和控制器层的基础代码。自定义模板:支持用户自定义代码模板,满足不同项目的特定需求。代码覆盖率:生成的代码符合项目编码规范,减少代码审查和维护的工作量。如何使用 EasyCode 快速生成代码下面,我们将通过具体步骤介绍如何使用 EasyCode 插件在 IntelliJ IDEA 中快速生成代码。连接数据库:确保您的项目已经配置好数据库连接。在 Database 工具窗口中,添加并连接到您的数据库。启动 EasyCode:在项目中,右键点击需要生成实体类的数据库表。选择 EasyCode > Generate Code。配置生成选项:在弹出的对话框中,选择生成实体类的包路径、类名前缀或后缀等选项。选择是否使用 Lombok 注解(如 @Data、@Builder 等)。生成代码:点击 Generate 按钮,EasyCode 将根据数据库表结构自动生成对应的实体类。生成 DAO 层代码选择实体类:在项目视图中,选择刚生成的实体类。启动 DAO 生成:右键点击实体类,选择 EasyCode > Generate。配置生成选项:选择需要生成的包路径。选择使用的 ORM 框架(如 MyBatis、JPA 等)。生成代码:点击 Generate,插件将自动生成 Mapper 接口和相应的 XML 配置文件。由于我的controller层在另一个模块,所以没有生成,可以分两次生成
5个月前
284
0
1
数据库加密工具类编写(springboot)
在配置文件中,明文编写一些敏感数据是不安全的,所以通常会进行加密,这里我使用druid连接池的工具来进行加密处理package com.jingdianjichi.subject.infra.basic.service.utils; import com.alibaba.druid.filter.config.ConfigTools; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; public class DruidEncryptUtil { private static String publicKey; private static String privateKey; static { try { String[] keyPair = ConfigTools.genKeyPair(512); privateKey = keyPair[0]; System.out.println("privateKey:" + privateKey); publicKey = keyPair[1]; System.out.println("publicKey:" + publicKey); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { throw new RuntimeException(e); } } public static String encrypt(String plainText) throws Exception { String encrypt = ConfigTools.encrypt(privateKey, plainText); System.out.println("encrypt:" + encrypt); return encrypt; } public static String decrypt(String encryptText) throws Exception { String decrypt = ConfigTools.decrypt(publicKey, encryptText); System.out.println("decrypt:" + decrypt); return decrypt; } public static void main(String[] args) throws Exception { //这里我设置的密码是123456 String encrypt = encrypt("123456"); System.out.println("encrypt:" + encrypt); } } 运行此类后,控制台将打印出私钥和公钥以及解密后的密文,随后将相应数据填入yml配置文件中。password放密文;publicKey放公钥;还需要配置config:enabled以及connect-propertie;如下所示server: port: 3000 spring: datasource: username: root password: da6IO6pMIxKQS2Ir2E2WHVChJCBM++Jj86xWX8QFUC9P8GWwVmUI6JcC9eiS4CvC6OYdslgQX0CS0Bkr+9VGhQ== url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&useSSL=true driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: # 初始的连接数量 initial-size: 20 # 最小的空闲连接数 min-idle: 20 # 最大的活动连接数 max-active: 100 # 最大等待时间 max-wait: 60000 # 启用统计功能 stat-view-servlet: enabled: true # 统计功能的URL模式 url-pattern: /druid/* # 登录名 login-username: admin # 登录密码 login-password: 123456 # 过滤器 filter: # 统计过滤器 stat: enabled: true # 超过多少毫秒算慢sql slow-sql-millis: 2000 # 是否记录慢sql log-slow-sql: true # 墙过滤器 wall: enabled: true # 开启配置以进行加密处理,开启之后connect-properties才会被读取执行 config: enabled: true connect-properties: # 配置加密 config.decrypt: true # 配置解密密钥 config.decrypt.key: ${publicKey} publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIf+6C47xT62o5CeybxZFZI6D+Z64SUJT22U3jBeqGCaRM5HE1ic1oP3PAdpQ2nBVKqAWDqf/tpzBqzAxw/lUEcCAwEAAQ==
11个月前
303
0
2
Vue 3 和 Element Plus 实现商品管理系统 - 表单校验部分解析
介绍在本博客中,我们将深入探讨如何使用 Vue 3 和 Element Plus 构建一个简单的商品管理系统,并重点关注表单校验的部分。这个系统允许用户添加、编辑和删除商品,以及对商品进行搜索。技术栈在这个项目中,我们使用了以下技术:Vue 3:一个流行的 JavaScript 框架,用于构建用户界面。Element Plus:一套基于 Vue 3 的组件库,用于创建漂亮的用户界面。Axios:一个用于处理 HTTP 请求的 JavaScript 库。表单校验在这个项目中,我们使用 Element Plus 的表单组件来实现商品信息的输入和校验。以下是与表单校验相关的关键知识点和注意事项:1. 引入 Element Plus在项目中首先要确保已正确引入 Element Plus,以便使用它的表单组件和验证规则。import { ref, reactive } from "vue"; import { ElForm, ElFormItem, ElInput, ElSelect, ElOption } from "element-plus";2. 创建表单数据和校验规则我们使用 ref 来创建表单数据,并使用 ref 来创建校验规则。校验规则通常包括字段的必填性、数据类型和自定义校验方法。const insertForm = ref({ sellerID: "", name: "", description: "", price: "", category: "", condition: "", quantity: "", // status: "", }); const insertFormRules = ref({ name: [ { required: true, message: "商品名称不能为空", trigger: "blur", }, ], description: [ { required: true, message: "商品描述不能为空", trigger: "blur", }, ], price: [ { required: true, validator: validatePrice, trigger: "blur", }, ], category: [ { required: true, message: "请选择商品类别", trigger: "change", }, ], condition: [ { required: true, message: "请选择商品成色", trigger: "change", }, ], quantity: [ { required: true, message: "商品数量不能为空", trigger: "blur", }, { type: "number", message: "商品数量必须为数字值", }, ], });3. 表单校验在提交表单之前,我们使用 el-form 的 validate 方法来进行表单校验。校验成功后才允许提交数据。<el-dialog v-model="dialogInsertFormVisible" title="上架商品"> <el-form ref="insertFormRulesRef" :model="insertForm" :rules="insertFormRules" > <el-form-item label="商品名称" label-width="80px" prop="name"> <el-input v-model="insertForm.name" autocomplete="off" /> </el-form-item> <el-form-item label="描述" label-width="80px" prop="description"> <el-input v-model="insertForm.description" autocomplete="off" /> </el-form-item> <el-form-item label="价格" label-width="80px" prop="price"> <el-input v-model="insertForm.price" autocomplete="off" /> </el-form-item> <el-form-item label="类别" label-width="80px" prop="category"> <el-select v-model="insertForm.category" placeholder="请选择类别"> <el-option label="服饰鞋帽" value="服饰鞋帽" /> <el-option label="家居用品" value="家居用品" /> <el-option label="电子数码" value="电子数码" /> <el-option label="美妆护肤" value="美妆护肤" /> <el-option label="食品生鲜" value="食品生鲜" /> <el-option label="图书音像" value="图书音像" /> <el-option label="儿童玩具" value="儿童玩具" /> <el-option label="运动户外" value="运动户外" /> <el-option label="汽车用品" value="汽车用品" /> <el-option label="医疗保健" value="医疗保健" /> <el-option label="工艺礼品" value="工艺礼品" /> <el-option label="虚拟物品" value="虚拟物品" /> </el-select> </el-form-item> <el-form-item label="成色" label-width="80px" prop="condition"> <el-select v-model="insertForm.condition" placeholder="请选择成色"> <el-option label="全新" value="全新" /> <el-option label="99新" value="99新" /> <el-option label="95新" value="95新" /> <el-option label="9成新" value="9成新" /> <el-option label="8成新" value="8成新" /> <el-option label="6成新" value="6成新" /> </el-select> </el-form-item> <el-form-item label="数量" label-width="80px" prop="quantity"> <el-input v-model.number="insertForm.quantity" autocomplete="off" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogInsertFormVisible = false">取消</el-button> <el-button type="primary" @click="submitItemInform(insertFormRulesRef)" > 提交 </el-button> <el-button type="primary" @click="test"> 提交 </el-button> </span> </template> </el-dialog>ref[0].validate(async (valid) => { if (valid) { // 表单校验通过,可以提交数据 try { const res = await axios.post( "http://localhost:8080/userInsertItem", insertForm.value ); // 处理提交结果... } catch (err) { // 处理请求错误... } } else { // 表单校验不通过,不执行提交操作 console.log("表单校验不通过!"); } });4. 自定义校验规则在校验规则中,我们可以使用自定义校验方法来实现特定的验证逻辑。例如,我们可以编写一个验证价格是否为数字的自定义校验方法:const validatePrice = (rule, value, callback) => { if (!value) return callback(new Error("请输入金额")); if (!Number(value)) return callback(new Error("请输入数字值")); let reg = /((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/; if (!reg.test(value)) return callback(new Error("请输入正确价格")); callback(); };然后,在校验规则中应用该自定义校验方法:price: [ { required: true, validator: validatePrice, trigger: "blur", }, ],5. 提示用户在校验不通过时,使用 Element Plus 的消息提示功能来通知用户错误信息:if (!valid) { // 表单校验不通过,显示错误消息 this.$message.error("表单校验不通过,请检查输入!"); }6. 表单重置在提交成功后,你可以选择重置表单,以便用户继续添加新的商品信息:ref[0].resetFields(); // 重置表单总结在这篇博客中,我们深入探讨了如何使用 Vue 3 和 Element Plus 构建商品管理系统的表单校验部分。我们学习了如何创建表单数据、定义校验规则、进行表单校验以及处理校验结果。此外,我们还介绍了如何使用自定义校验方法和提示用户错误信息的方法。这个项目只是一个简单的示例,你可以根据实际需求扩展和定制更多功能,以满足你的项目要求。希望这篇博客对你有所帮助,如果有任何问题或建议,请随时留言。
1年前
638
1
1
1
2
3
Charlotte
54
文章数
17
标签数
50
评论量
在unity中使用c#语言实现人物的转身
Spring与SpringMVC注解总览
使用Spring MVC进行RESTful开发
人生倒计时
热门文章
1
动漫分享---《想要成为影之实力者》
1418 阅读 - 10/11
2
在unity中使用c#语言实现人物的转身
1396 阅读 - 10/13
3
可恶的日本军国主义!我们一定不能遗忘这段历史,遗忘历史就意味着背叛!!!!
1331 阅读 - 10/17
标签云
java
追番~~
计网
c#
unity
脆皮大学生
spring AOP
博客更新
selenium
web测试
springboot
ES6
vue3
elementPlus
idea
舔狗日记