作者 钟来

批量添加新增id返回

水产时价信息网的鱼价信息采集
package com.zhonglai.luhui.datasource.config;
import com.ruoyi.common.utils.StringUtils;
import com.zhonglai.luhui.datasource.plugin.GeneratedKeyInterceptor;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
... ... @@ -131,6 +135,9 @@ public class MyBatisConfig
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
sessionFactory.setPlugins(new Interceptor[]{
new GeneratedKeyInterceptor()
});
//创建一个MapperHelper
MapperHelper mapperHelper = new MapperHelper();
... ... @@ -160,4 +167,15 @@ public class MyBatisConfig
return sessionFactory.getObject();
}
@Bean
public Interceptor generatedKeyInterceptor() {
return new GeneratedKeyInterceptor();
}
@Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer(Interceptor generatedKeyInterceptor) {
return configuration -> configuration.addInterceptor(generatedKeyInterceptor);
}
}
\ No newline at end of file
... ...
package com.zhonglai.luhui.datasource.plugin;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
@Intercepts({
@Signature(
type = StatementHandler.class,
method = "update",
args = {Statement.class}
)
})
public class GeneratedKeyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler handler = (StatementHandler) invocation.getTarget();
MetaObject meta = SystemMetaObject.forObject(handler);
MappedStatement ms = (MappedStatement) meta.getValue("delegate.mappedStatement");
if (ms == null || ms.getSqlCommandType() != SqlCommandType.INSERT) {
return invocation.proceed();
}
Object paramObj = meta.getValue("delegate.boundSql.parameterObject");
List<?> list = extractList(paramObj);
if (list == null || list.isEmpty()) {
return invocation.proceed();
}
// 执行插入
Object result = invocation.proceed();
// 从 Statement 里读取生成的 keys,并回写到集合对象
Statement stmt = (Statement) invocation.getArgs()[0];
try (ResultSet rs = stmt.getGeneratedKeys()) {
String pkName = resolvePkName(list.get(0));
if (pkName == null) {
return result; // 无法解析主键名,跳过
}
int idx = 0;
while (rs != null && rs.next() && idx < list.size()) {
Object keyVal = rs.getObject(1);
setFieldValue(list.get(idx), pkName, keyVal);
idx++;
}
} catch (Exception ignore) {
// 不应该抛出,保证插入不受影响;若需要可记录日志
}
return result;
}
@SuppressWarnings("rawtypes")
private List extractList(Object param) {
if (param == null) return null;
if (param instanceof List) return (List) param;
if (param instanceof Map) {
Map map = (Map) param;
// MyBatis 对未指定 name 的 collection 参数可能为 "list" 或 "collection"
if (map.get("list") instanceof List) return (List) map.get("list");
if (map.get("collection") instanceof List) return (List) map.get("collection");
// 支持 @Param("list")
for (Object v : map.values()) {
if (v instanceof List) return (List) v;
}
}
return null;
}
private String resolvePkName(Object obj) {
Class<?> cls = obj.getClass();
// 查找带 @Id 注解的字段(javax.persistence 或其它同名注解)
List<Field> list = getAllFields(cls);
for (Field f : list) {
for (Annotation a : f.getAnnotations()) {
String an = a.annotationType().getSimpleName();
if ("Id".equals(an) || "TableId".equals(an)) {
return f.getName();
}
}
}
// 回退到常见命名
for (Field f : list) {
if ("id".equalsIgnoreCase(f.getName())) return f.getName();
}
return null;
}
private List<Field> getAllFields(Class<?> cls) {
List<Field> fields = new ArrayList<>();
Class<?> cur = cls;
while (cur != null && cur != Object.class) {
Collections.addAll(fields, cur.getDeclaredFields());
cur = cur.getSuperclass();
}
return fields;
}
private void setFieldValue(Object target, String fieldName, Object value) {
try {
Field f = findField(target.getClass(), fieldName);
if (f == null) return;
f.setAccessible(true);
Class<?> type = f.getType();
Object converted = convertValue(value, type);
f.set(target, converted);
} catch (Exception ignored) {
}
}
private Field findField(Class<?> cls, String name) {
Class<?> cur = cls;
while (cur != null && cur != Object.class) {
try {
return cur.getDeclaredField(name);
} catch (NoSuchFieldException e) {
cur = cur.getSuperclass();
}
}
return null;
}
private Object convertValue(Object val, Class<?> targetType) {
if (val == null) return null;
if (targetType.isAssignableFrom(val.getClass())) return val;
if (Number.class.isAssignableFrom(val.getClass()) || val instanceof Number) {
Number n = (Number) val;
if (targetType == Long.class || targetType == long.class) return n.longValue();
if (targetType == Integer.class || targetType == int.class) return n.intValue();
if (targetType == Short.class || targetType == short.class) return n.shortValue();
if (targetType == Byte.class || targetType == byte.class) return n.byteValue();
}
// 最后回退到字符串再尝试解析简单类型
String s = val.toString();
if (targetType == String.class) return s;
try {
if (targetType == Long.class || targetType == long.class) return Long.parseLong(s);
if (targetType == Integer.class || targetType == int.class) return Integer.parseInt(s);
if (targetType == Short.class || targetType == short.class) return Short.parseShort(s);
if (targetType == Byte.class || targetType == byte.class) return Byte.parseByte(s);
} catch (Exception ignored) {
}
return val;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// no-op
}
}
... ...
... ... @@ -81,9 +81,8 @@ public abstract class AquaticPublicOpinionBase implements AquaticPublicOpinionS
//保存文件
for (FishAquaticPublicOpinion aquaticPublicOpinion:list)
{
Map<String,Object> map = publicService.getObjectList(aquaticPublicOpinion,"id,info_url",null,null,0,0).get(0);
String text = getInfo((String) map.get("info_url"));
updateSaveInfo(text, (Integer) map.get("id"));
String text = getInfo(aquaticPublicOpinion.getInfoUrl());
updateSaveInfo(text, aquaticPublicOpinion.getId());
}
}
}
... ...
... ... @@ -2,9 +2,11 @@ package com.ruoyi.quartz.task.aquatic;
import cn.hutool.http.HttpUtil;
import com.ruoyi.system.domain.fish.FishAquaticPublicOpinion;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class ZnyjNftecAgriCn extends AquaticPublicOpinionBase{
@Override
List<FishAquaticPublicOpinion> collect(String day, Set<String> dedupMap) {
... ... @@ -17,7 +19,7 @@ public class ZnyjNftecAgriCn extends AquaticPublicOpinionBase{
aquaticPublicOpinion.setCreateTime(new Date());
aquaticPublicOpinion.setAquaticType(4);
list.add(aquaticPublicOpinion);
return Collections.emptyList();
return list;
}
@Override
... ...
... ... @@ -37,7 +37,7 @@ public interface IIotTerminalService
* @return 结果
*/
public int insertIotTerminal(IotTerminal iotTerminal);
public int updateIotTerminalOrderBy(String id,Integer order_by);
int addIotTerminals(Integer userId, List<String> ids);
/**
... ...
... ... @@ -102,6 +102,15 @@ public class IotTerminalServiceImpl implements IIotTerminalService
* @return 结果
*/
@Override
public int updateIotTerminalOrderBy(String id,Integer order_by)
{
IotTerminal iotTerminal = new IotTerminal();
iotTerminal.setId(id);
iotTerminal.setOrder_by(order_by);
return iotTerminalMapper.updateIotTerminal(iotTerminal);
}
@Override
public int updateIotTerminal(IotTerminal iotTerminal)
{
DeviceCommandApi deviceCommandApi = new DeviceCommandApi();
... ...
... ... @@ -97,6 +97,13 @@
<groupId>com.zhonglai.luhui</groupId>
<artifactId>lh-user</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
... ...
... ... @@ -115,4 +115,12 @@ public class IotTerminalController extends BaseController
{
return toAjax(iotTerminalService.deleteIotTerminalByIds(ids));
}
@ApiOperation("修改终端排序")
@Log(title = "终端", businessType = BusinessType.UPDATE)
@PostMapping("editOrderBy")
public AjaxResult editOrderBy(@RequestBody IotTerminal iotTerminal)
{
return toAjax(iotTerminalService.updateIotTerminalOrderBy(iotTerminal.getId(),iotTerminal.getOrder_by()));
}
}
... ...
# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: E:/work/idea/Luhui/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 119.23.218.181 # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-admin # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/tool/gen/generatorCodeFromDb,/data/**,/monitor/server/upload,/monitor/server/getSysMonitorServerList,/monitor/server/getSysMonitorServerLogList,/monitor/server/getNowAquaticPublicOpinion # NameServer地址 rocketmq: name-server: 8.129.224.117:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1 task: tesseract-path: E:/work/idea/Luhui/tessdata
\ No newline at end of file
# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: E:/work/idea/Luhui/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 127.0.0.1 # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-admin # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/tool/gen/generatorCodeFromDb,/data/**,/monitor/server/upload,/monitor/server/getSysMonitorServerList,/monitor/server/getSysMonitorServerLogList,/monitor/server/getNowAquaticPublicOpinion # NameServer地址 rocketmq: name-server: 8.129.224.117:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1 task: tesseract-path: E:/work/idea/Luhui/tessdata
\ No newline at end of file
... ...
package com.zhonglai.luhui.admin;
import com.ruoyi.quartz.task.AquaticPublicOpinionTask;
import com.ruoyi.quartz.task.aquatic.AquaticPublicOpinionService;
import com.ruoyi.quartz.task.aquatic.ZnyjNftecAgriCn;
import com.ruoyi.system.domain.sys.SysConfig;
import com.zhonglai.luhui.dao.service.PublicService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest(classes = AdminApplication.class)
class AquaticPublicOpinionTaskTestTest {
@Autowired
private ZnyjNftecAgriCn znyjNftecAgriCn;
@Test
public void testRun() {
//初始微信采集服务
znyjNftecAgriCn.run("20260105");
}
}
... ...
... ... @@ -686,25 +686,12 @@
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<name>luhui nexus</name>
<url>http://120.25.223.227:4781/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
\ No newline at end of file
... ...