代码生成器实现
代码生成器实现
实现封装元数据的工具类实现代码生成器的代码编写掌握模板创建的
构造数据模型
需求分析
借助Freemarker机制可以方便的根据模板生成文件,同时也是组成代码生成器的核心部分。对于Freemarker而
言,其强调 数据模型 + 模板 = 文件 的思想,所以代码生成器最重要的一个部分之一就是数据模型。在这里数据
模型共有两种形式组成:
- 数据库中表、字段等信息
针对这部分内容,可以使用元数据读取并封装到java实体类中
- 用户自定义的数据
为了代码生成器匹配多样的使用环境,可以让用户自定义的数据,并且以key-value的形式配置到properties文件中
接下来针对这两方面的数据进行处理
PropertiesUtils工具类自定义数据
通过PropertiesUtils工具类,统一对properties文件夹下的所有.properties文件进行加载,并存入内存中
package cn.itcast.generate.utils;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;/*** 需要将自定义的配置信息写入到properties文件中* 配置到相对于工程的properties文件夹下*/
public class PropertiesUtils {public static Map<String,String> customMap = new HashMap<>();static {File dir = new File("properties");try {List<File> files = FileUtils.searchAllFile(new File(dir.getAbsolutePath()));for (File file : files) {if(file.getName().endsWith(".properties")) {Properties prop = new Properties();prop.load(new FileInputStream(file));customMap.putAll((Map) prop);}}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {PropertiesUtils.customMap.forEach((k, v)->{System.out.println(k+"--"+v);});}
}
骚戴理解:这里的PropertiesUtils工具类的作用就是把properties文件夹下的所有.properties文件读取处理,主要就是用于用户自定义的数据,可能有的数据不是从数据库里面读取的,所以就可以定义在properties配置文件里,然后读取配置文件获取数据,再加载到模板里面
导入代码生成器依赖的配置文件
#SQL类型和java类型替换规则
VARCHAR=String
BIGINT=Long
INT=Integer
DATE=java.util.Date
DATETIME=java.util.Date
DOUBLE=Double
TEXT=String
VARCHAR2=String
NVARCHAR2=String
NUMBER=Long
CHAR=String
MEDIUMTEXT=String
TINYINT=Integer
LONGTEXT=String#Table的前缀或者后缀
tableRemovePrefixes=tb_,co_,pe_,bs_
元数据处理
加载指定数据库表,将表信息转化为实体类对象(Table)
package cn.itcast.generate.utils;import cn.itcast.generate.entity.Column;
import cn.itcast.generate.entity.DataBase;
import cn.itcast.generate.entity.Table;import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;public class DataBaseUtils {//获取到mysql中所有的数据库名称//获取数据库连接public static Connection getConnection(DataBase db) throws Exception {Properties props = new Properties();props.put("remarksReporting","true");//获取数据库的备注信息props.put("user",db.getUserName());props.put("password",db.getPassWord());Class.forName(db.getDriver());//注册驱动return DriverManager.getConnection(db.getUrl(),props);}//获取数据库列表public static List<String> getSchemas(DataBase db) throws Exception {//1.获取元数据Connection connection = getConnection(db);DatabaseMetaData metaData = connection.getMetaData();//2.获取所有数据库列表ResultSet rs = metaData.getCatalogs();List<String> list = new ArrayList<>();while (rs.next()) {list.add(rs.getString(1));}rs.close();connection.close();return list;}/*** 获取数据库中的表和字段构造实体类* Table对象** 1.参数* DataBase 数据库对象* 2.操作步骤* 1.获取连接* 2.获取databasemetaData* 3.获取当前数据库中的所有表* 4.获取每个表中的所有字段* 5.封装到java对象中即可*/public static List<Table> getDbInfo(DataBase db) throws Exception {//1.获取连接Connection connection = getConnection(db);//2.获取元数据DatabaseMetaData metaData = connection.getMetaData();//3.获取当前数据库中的所有表ResultSet tables = metaData.getTables(null, null, "pe_permission", new String[]{"TABLE"});List<Table> list = new ArrayList<>();while (tables.next()) {Table tab = new Table();//i.表名String tableName = tables.getString("TABLE_NAME"); //bs_user User//ii.类名String className = removePrefix(tableName);//iii.描述String remarks = tables.getString("REMARKS");//iiii.主键(主键可能是组合主键,有多个,所以primaryKeys是多个主键的set集合)ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);String keys = "";while (primaryKeys.next()) {String keyname = primaryKeys.getString("COLUMN_NAME");keys += keyname+",";}tab.setName(tableName);tab.setName2(className);tab.setComment(remarks);tab.setKey(keys);//处理表中的所有字段ResultSet columns = metaData.getColumns(null, null, tableName, null);List <Column> columnList = new ArrayList<>();while (columns.next()) {Column cn = new Column();//构造Column对象//列名称String columnName = columns.getString("COLUMN_NAME"); //user_id userId , create_time createTimecn.setColumnName(columnName);//属性名String attName = StringUtils.toJavaVariableName(columnName);cn.setColumnName2(attName);//java类型和数据库类型String dbType = columns.getString("TYPE_NAME");//VARCHAR,DATETIMEcn.setColumnDbType(dbType);String javaType = PropertiesUtils.customMap.get(dbType);cn.setColumnType(javaType);//备注String columnRemark = columns.getString("REMARKS");//VARCHAR,DATETIMEcn.setColumnComment(columnRemark);//是否主键String pri = null;if(StringUtils.contains(columnName ,keys.split(","))) {pri = "PRI";}cn.setColumnKey(pri);columnList.add(cn);}columns.close();tab.setColumns(columnList);list.add(tab);}tables.close();connection.close();return list;}public static String removePrefix(String tableName) {String prefix = PropertiesUtils.customMap.get("tableRemovePrefixes");//bs_, tb_ , co_ ,String temp = tableName; //bs_userfor(String pf : prefix.split(",")) {temp = StringUtils.removePrefix(temp,pf,true);}//temp = userreturn StringUtils.makeAllWordFirstLetterUpperCase(temp);}public static void main(String[] args) throws Exception {DataBase db = new DataBase("MYSQL","ihrm");db.setUserName("root");db.setPassWord("111111");List<Table> dbInfo = DataBaseUtils.getDbInfo(db);for (Table table : dbInfo) {List<Column> columns = table.getColumns();for (Column column : columns) {System.out.println(column);}}}
}
骚戴理解:removePrefix方法就是把数据库表名的前缀去掉,然后再转成首字母大写的实体类名称,表名前缀都写在了配置文件里面,所以先通过PropertiesUtils获取配置文件的前缀配置信息,如下所示,然后调用StringUtils的removePrefix方法去掉前缀,最后调用StringUtils的makeAllWordFirstLetterUpperCase方法转成首字母大写
#Table的前缀或者后缀
tableRemovePrefixes=tb_,co_,pe_,bs_
实现代码生成
需求分析
为了代码更加直观和易于调用,实现代码生成共有两个类组成:
- UI界面统一调用的入口类:GeneratorFacade
方便多种界面调用,主要完成数据模型获取,调用核心代码处理类完成代码生成
- 代码生成核心处理类:Generator
根据数据模型和模板文件路径,统一生成文件到指定的输出路径
模板生成
- 配置统一调用入口类GeneratorFacade
package cn.itcast.generate.core;import cn.itcast.generate.entity.DataBase;
import cn.itcast.generate.entity.Settings;
import cn.itcast.generate.entity.Table;
import cn.itcast.generate.utils.DataBaseUtils;
import cn.itcast.generate.utils.PropertiesUtils;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 1.采集用户UI界面输入的数据* 模板位置* 代码生成路径* 工程配置对象 setting* 数据库对象 DataBase* 2.准备数据模型* 1.自定义配置* 2.元数据* 3.setting* 3.调用核心处理类完成代码生成工作* 方法:Generator*/
public class GeneratorFacade {private String templatePath;private String outPath;private Settings settings;private DataBase db;private Generator generator;public GeneratorFacade(String templatePath, String outPath, Settings settings, DataBase db) throws Exception {this.templatePath = templatePath;this.outPath = outPath;this.settings = settings;this.db = db;this.generator = new Generator(templatePath,outPath);}/*** 1.准备数据模型* 2.调用核心处理类完成代码生成工作*/public void generatorByDataBase() throws Exception {List<Table> tables = DataBaseUtils.getDbInfo(db);for (Table table : tables) {//对每一个Table对象进行代码生成/*** 数据模型* 调用Generator核心处理类*/Map<String,Object> dataModel = getDataModel(table);
//
// for(Map.Entry<String,Object> entry:dataModel.entrySet()) {
// System.out.println(entry.getKey() + "--" + entry.getValue());
// }
// System.out.println("------------------------");generator.scanAndGenerator(dataModel);}}/*** 根据table对象获取数据模型*/private Map<String,Object> getDataModel(Table table) {Map<String,Object> dataModel = new HashMap<>();//1.自定义配置dataModel.putAll(PropertiesUtils.customMap);//2.元数据dataModel.put("table",table); //table.name2//3.settingdataModel.putAll(this.settings.getSettingMap());//4.类型dataModel.put("ClassName",table.getName2());return dataModel;}
}
骚戴理解:通过DataBaseUtils.getDbInfo(db);获取到的是数据库表数据的元数据信息,getDataModel方法的作用是为了封装数据模型,数据模型结合模板生成代码,数据模型包括自定义配置、元数据、setting里面的数据,而ClassName只是为了方便后面拿这个类名而已,所以也封装在其中
- 处理模板代码生成的核心类Generator
package cn.itcast.generate.core;import cn.itcast.generate.utils.FileUtils;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 代码生成器的核心处理类* 使用Freemarker完成文件生成* 数据模型 + 模板* 数据:* 数据模型* 模板的位置* 生成文件的路径**/
public class Generator {private String templatePath;//模板路径private String outPath;//代码生成路径private Configuration cfg;public Generator(String templatePath, String outPath) throws Exception {this.templatePath = templatePath;this.outPath = outPath;//实例化Configuration对象cfg = new Configuration();//指定模板加载器FileTemplateLoader ftl = new FileTemplateLoader(new File(templatePath));cfg.setTemplateLoader(ftl);}/*** 代码生成* 1.扫描模板路径下的所有模板* 2.对每个模板进行文件生成(数据模型)*/public void scanAndGenerator(Map<String,Object> dataModel) throws Exception {//1.根据模板路径找到此路径下的所有模板文件List<File> fileList = FileUtils.searchAllFile(new File(templatePath));//2.对每个模板进行文件生成for (File file : fileList) {executeGenertor(dataModel,file);}}/*** 对模板进行文件生成* @param dataModel : 数据模型* @param file : 模板文件* 模板文件:c:com.ihrm.system.abc.java*/private void executeGenertor(Map<String,Object> dataModel,File file) throws Exception {//1.文件路径处理 (E:\模板\${path1}\${path2}\${path3}\${ClassName}.java)//templatePath : E:\模板\String templateFileName = file.getAbsolutePath().replace(this.templatePath,"");String outFileName = processTemplateString(templateFileName,dataModel);//2.读取文件模板Template template = cfg.getTemplate(templateFileName);template.setOutputEncoding("utf-8");//指定生成文件的字符集编码//3.创建文件File file1 = FileUtils.mkdir(outPath, outFileName);//4.模板处理(文件生成)FileWriter fw = new FileWriter(file1);template.process(dataModel,fw);fw.close();}public String processTemplateString(String templateString,Map dataModel) throws Exception {StringWriter out = new StringWriter();Template template = new Template("ts",new StringReader(templateString),cfg);template.process(dataModel,out);return out.toString();}public static void main(String[] args) throws Exception {String templatePath = "C:\\Users\\ThinkPad\\Desktop\\ihrm\\day13\\资源\\测试\\模板";String outPath = "C:\\Users\\ThinkPad\\Desktop\\ihrm\\day13\\资源\\测试\\生成代码路径";Generator generator = new Generator(templatePath, outPath);Map <String,Object> dataModel = new HashMap<>();dataModel.put("username","张三");generator.scanAndGenerator(dataModel);}}
骚戴理解:executeGenertor方法这段代码的作用是根据模板文件和数据模型生成代码文件。
1. String templateFileName = file.getAbsolutePath().replace(this.templatePath,"");
这行代码的作用是将模板文件的绝对路径中的模板根路径(即templatePath)替换为空字符串,得到模板文件名(不包含根路径)。
2. String outFileName = processTemplateString(templateFileName,dataModel);
这行代码的作用是将模板文件名中的变量替换为具体的值,得到输出文件的文件名。
3. Template template = cfg.getTemplate(templateFileName);
这行代码的作用是根据模板文件名,从Configuration对象中获取对应的Template对象。
4. template.setOutputEncoding("utf-8");
这行代码的作用是指定生成文件的字符集编码为UTF-8。
5. File file1 = FileUtils.mkdir(outPath, outFileName);
这行代码的作用是根据输出路径和输出文件名,创建输出文件。
6. FileWriter fw = new FileWriter(file1);
这行代码的作用是创建一个FileWriter对象,用于将模板处理后的结果输出到指定的文件中。
7. template.process(dataModel,fw);
这行代码的作用是将数据模型和FileWriter对象作为参数传入Template的process方法中,根据数据模型中的值,将模板文件中的变量替换为具体的值,并将输出结果写入FileWriter对象中。
8. fw.close();
这行代码的作用是关闭FileWriter对象,释放资源。
路径处理
使用字符串模板对文件生成路径进行统一处理
public String processTemplateString(String templateString,Map dataModel) throws Exception {StringWriter out = new StringWriter();Template template = new Template("ts",new StringReader(templateString),cfg);template.process(dataModel,out);return out.toString();}
骚戴理解:这段代码是使用FreeMarker模板引擎来处理模板字符串,将模板字符串中的变量替换为具体的值,最终返回替换后的字符串。
1.StringWriter out = new StringWriter();
这行代码的作用是创建一个StringWriter对象,用于接收模板处理后的输出结果。
2.Template template = new Template("ts",new StringReader(templateString),cfg);
这行代码的作用是创建一个Template对象,用于解析模板字符串并进行变量替换。其中,第一个参数是模板名称(随意取名),第二个参数是StringReader对象,用于读取模板字符串,第三个参数是Configuration对象,用于配置模板引擎的相关参数。
3.template.process(dataModel,out);
这行代码的作用是将数据模型和输出流作为参数传入Template的process方法中,根据数据模型中的值,将模板字符串中的变量替换为具体的值,并将输出结果写入输出流。
4.return out.toString();
这行代码的作用是将输出流中的内容转换为字符串,并返回该字符串。
制作模板
模板制作的约定
- 模板位置
模板统一放置到相对于当前路径的模板文件夹下
- 自定义数据
自定义的数据以 .propeties 文件(key-value)的形式存放入相对于当前路径的 properties 文件夹下
- 数据格式
名称 | 说明 |
author | 作者 |
project | 工程名 |
path1 | 包名1 |
path2 | 包名2 |
path3 | 包名3 |
pPackage | 完整包名 |
projectComment | 工程描述 |
ClassName | 类名 |
table | 数据库信息 |
table中数据内容:
name | 表名 |
comment | 表注释 |
key | 表主键 |
columns | 所有列信息 |
columnName | 字段列名 |
columnName2 | 属性名 |
columnType | java类型 |
columnDbType | 数据库类型 |
columnComment | 注释 |
columnKey | 是否主键 |
需求分析
制作通用的SpringBoot程序的通用模板
- 实体类
类路径,类名,属性列表(getter,setter方法)
- 持久化层
类路径,类名,引用实体类
- 业务逻辑层
类路径,类名,引用实体类,引用持久化层代码
- 视图层
类路径,类名,引用实体类,引用业务逻辑层代码,请求路径
- 配置文件
pom文件,springboot配置文件
SpringBoot通用模板
实体类
package ${pPackage}.pojo;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;@Entity
@Table(name = "${table.name}")
public class ${ClassName} implements Serializable {//这里table.columns是因为上面数据模型里面放的是 dataModel.put("table",table);<#list table.columns as column><#if column.columnKey??>@Id</#if>private ${column.columnType} ${column.columnName2};</#list><#list table.columns as column>public void set${column.columnName2?cap_first}(${column.columnType} value) {this.${column.columnName2} = value;}public ${column.columnType} get${column.columnName2?cap_first}() {return this.${column.columnName2};}</#list>
}
骚戴理解:这段代码使用FreeMarker模板语言生成Java类的属性和getter/setter方法。
具体来说,这段代码包含了以下两个部分:
1. 属性生成部分
-<#list table.columns as column>:这行代码使用FreeMarker的list指令,遍历数据模型中的table.columns字段,将每个元素赋值给变量column。
-<#if column.columnKey??>:这行代码使用FreeMarker的if指令,判断当前列是否为主键列。
-@Id:如果当前列是主键列,则生成@Id注解。
-<#if>:if指令的结束标签。
-private ${column.columnType} ${column.columnName2};:生成Java类的私有属性,属性名和属性类型分别对应数据模型中的column.columnName2和column.columnType。
-</#list>:list指令的结束标签。
2. getter/setter方法生成部分
-<#list table.columns as column>:这行代码使用FreeMarker的list指令,遍历数据模型中的table.columns字段,将每个元素赋值给变量column。
-public void set${column.columnName2?cap_first}(${column.columnType} value) {:生成Java类的setter方法,方法名为set+属性名(首字母大写),方法参数类型和属性类型相同,方法体为将参数值赋值给属性,其中?cap_first是使用内置函数,可以把column.columnName2变成首字母大写。
-public ${column.columnType} get${column.columnName2?cap_first}() {:生成Java类的getter方法,方法名为get+属性名(首字母大写),方法返回值类型为属性类型,方法体为返回属性值。
-</#list>:list指令的结束标签。
总之,这段代码的作用是根据数据模型中的表结构信息,生成Java类的属性和getter/setter方法。
Service层
<#assign classNameLower = ClassName ? uncap_first>
package ${pPackage}.service;import com.ihrm.common.utils.IdWorker;
import ${pPackage}.dao.${ClassName}Dao;
import ${pPackage}.pojo.${ClassName};
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class ${ClassName}Service {@Autowiredprivate ${ClassName}Dao ${classNameLower}Dao;@Autowiredprivate IdWorker idWorker;/*** 保存*/public void add(${ClassName} ${classNameLower}) {//基本属性的设置String id = idWorker.nextId()+"";${classNameLower}.setId(id);${classNameLower}Dao.save(${classNameLower});}/*** 更新*/public void update(${ClassName} ${classNameLower}) {${classNameLower}Dao.save(${classNameLower});}/*** 删除*/public void deleteById(String id) {${classNameLower}Dao.deleteById(id);}/*** 根据id查询*/public ${ClassName} findById(String id) {return ${classNameLower}Dao.findById(id).get();}/*** 查询列表*/public List<${ClassName}> findAll() {return ${classNameLower}Dao.findAll();}
}
Controller层
<#assign classNameLower = ClassName ? uncap_first>
package ${pPackage}.controller;import com.ihrm.common.entity.Result;
import com.ihrm.common.entity.ResultCode;
import com.ihrm.common.exception.CommonException;import ${pPackage}.service.${ClassName}Service;
import ${pPackage}.pojo.${ClassName};
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;//解决跨域问题
@CrossOrigin
@RestController
@RequestMapping(value="/${classNameLower}")
public class ${ClassName}Controller {@Autowiredprivate ${ClassName}Service ${classNameLower}Service;//保存@RequestMapping(value="",method = RequestMethod.POST)public Result save(@RequestBody ${ClassName} ${classNameLower}) {//业务操作${classNameLower}Service.add(${classNameLower});return new Result(ResultCode.SUCCESS);}//根据id更新@RequestMapping(value = "/{id}",method = RequestMethod.PUT)public Result update(@PathVariable(value="id") String id, @RequestBody ${ClassName} ${classNameLower} ) {//业务操作${classNameLower}.setId(id);${classNameLower}Service.update(${classNameLower});return new Result(ResultCode.SUCCESS);}//根据id删除@RequestMapping(value="/{id}",method = RequestMethod.DELETE)public Result delete(@PathVariable(value="id") String id) {${classNameLower}Service.deleteById(id);return new Result(ResultCode.SUCCESS);}//根据id查询@RequestMapping(value="/{id}",method = RequestMethod.GET)public Result findById(@PathVariable(value="id") String id) throws CommonException {${ClassName} ${classNameLower} = ${classNameLower}Service.findById(id);return new Result(ResultCode.SUCCESS,${classNameLower});}//查询全部@RequestMapping(value="",method = RequestMethod.GET)public Result findAll() {List<${ClassName}> list = ${classNameLower}Service.findAll();Result result = new Result(ResultCode.SUCCESS);result.setData(list);return result;}
}
Dao层
package ${pPackage}.dao;import ${pPackage}.pojo.${ClassName};
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;public interface ${ClassName}Dao extends JpaRepository<${ClassName},String> ,JpaSpecificationExecutor<${ClassName}> {
}
配置文件
- application.yml
server: port: 9001
spring: application: name: ${project}-${path3} #指定服务名datasource: driverClassName: ${driverName}url: ${url}username: ${dbuser}password: ${dbpassword}jpa: database: MySQLshow-sql: true
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>${path2}_parent</artifactId><groupId>${path1}.${path2}</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>${path2}_${project}</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>${path1}.${path2}</groupId><artifactId>${path2}_common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>
</project>
相关文章:
代码生成器实现
代码生成器实现 实现封装元数据的工具类实现代码生成器的代码编写掌握模板创建的 构造数据模型 需求分析 借助Freemarker机制可以方便的根据模板生成文件,同时也是组成代码生成器的核心部分。对于Freemarker而 言,其强调 数据模型 模板 文件 的思…...
【Python基础】Python函数(基本函数)
文章目录 Python函数1、函数多返回值2、函数多种传参方式(1)位置参数(2)关键字参数(3)缺省参数(4)不定长参数位置传递关键字传递 3、小结 Python函数 1、函数多返回值 Q:如果一个函数要有多个返回值,该如何书写代码? # 使用多个变量&#…...
Vue3 + TS + Vite —— 大屏可视化 项目实战
前期回顾 Vue3 Ts Vite pnpm 项目中集成 —— eslint 、prettier、stylelint、husky、commitizen_彩色之外的博客-CSDN博客搭建VIte Ts Vue3项目并集成eslint 、prettier、stylelint、huskyhttps://blog.csdn.net/m0_57904695/article/details/129950163?spm1001.2014…...
EasyExcel 批量导入并校验数据
文章目录 前言一、pom二、使用步骤1.导入对象2.读入数据并保存 前言 EasyExcel 批量导入并校验数据 一、pom <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.7</version></depend…...
亚马逊、Allegro卖家建立属于自己的测评系统,实现批量优质账号养成
卖家搭建一套完整的测评系统,卖家自己能够养出批量优质账号,并完全掌控真实买家的浏览、加购、下单和评价等风控数据规律。我们的系统能够自主加速推广,防御反击,同时节省运营成本,实现高效的测评运营。 我们的系统支…...
springboot的目录结构作用
springboot单体项目结构大概如下。 代码都在src/main下, java是后端代码 java下最基本的包 dao(mapper) entity(model) service controller 其他的包根据项目需求扩展。 resources下是配置文件。 如果不是前后端分离,resources下放的是静态文件…...
微信小程序基础使用-请求数据并渲染
小程序基本使用-请求数据并渲染 小程序模板语法-数据绑定 在js中定义数据 Page({data: {isOpen: true,message: hello world!} })小程序的data是一个对象,不同于vue的data是一个函数 在模块中获取使用数据 小程序中使用 {{}} 实现数据与模板的绑定 内容绑定&a…...
代码随想录训练营Day55| 392.判断子序列 ;115.不同的子序列
392.判断子序列 class Solution {public boolean isSubsequence(String s, String t) {int m s.length();int n t.length();if(m>n) return false;int[][] dp new int[m1][n1];dp[0][0]0;for(int i1;i<m;i){for(int j1;j<n;j){if(s.charAt(i-1)t.charAt(j-1)){dp[i…...
网络作业9【计算机网络】
网络作业9【计算机网络】 前言推荐网络作业9一. 单选题(共12题,36分)二. 多选题(共1题,3分)三. 填空题(共2题,10分)四. 阅读理解(共1题,17分&…...
C++ QT 上传图片至mysql数据库
以下是一个简单的C QT上传图片至MySQL数据库的代码示例: #include <QtSql> #include <QFile> #include <QByteArray> int main() { //连接数据库 QSqlDatabase db QSqlDatabase::addDatabase("QMYSQL"); …...
2023去水印小程序saas系统源码修复独立版v1.0.3+uniapp前端
🎈 限时活动领体验会员:可下载程序网创项目短视频素材 🎈 🎉 有需要的朋友记得关赞评,阅读文章底部来交流!!! 🎉 ✨ 源码介绍 一个基于uniapp写的小程序,后端…...
【ChatGPT】数据科学 ChatGPT Cheat Sheet 书籍分享(阿里云盘下载)
封皮 以下为书中部分内容的机器翻译 我们的重要提示指南 1. 以 AI 角色的描述开始提示。 例如,“你是{x}”或“我希望你扮演{x}”。如果您不确定,请尝试“你是一个有帮助的助手”。 例如,您是 OpenAI 的数据科学家,您正在研究大型…...
使用 Docker-compose 搭建lnmp
服务编排: 应用编排: 单机环境下:shell/python脚本多机/集群环境下:ansible、saltstack、pubbet docker容器编排: 单机:docker-compose多机/集群:docker swarm,mesos marathon&a…...
chatgpt赋能python:Python中的矩阵合并方法:介绍和使用方法
Python中的矩阵合并方法: 介绍和使用方法 矩阵合并是Python编程中常用的操作之一,特别是针对数据分析、机器学习和深度学习等领域。Python提供了多种方法来合并矩阵,本文将介绍这些方法并分享如何在实际应用中使用它们。 普通矩阵合并 最基础的矩阵合…...
Java动态代理:优化静态代理模式的灵活解决方案
文章目录 代理模式定义具体实现分析优缺点 优化使用动态代理解决优化相关知识动态代理种类场景应用 代理模式 定义 代理模式,为其他对象提供一种代理以控制对这个对象的访问 具体实现 代理模式的具体实现描述可以分为以下几个步骤: 创建抽象对象接…...
四种Bootloader程序安全机制设计
正文 大家周末好,我是bug菌~ 不管是玩单片机还是嵌入式linux,基本上都会接触到bootloader,所以bootloader程序也是一个关键的组件,进行硬件初始化,应用程序的合法性、完成性检测、升级功能等等都与其息息相关。 像一些…...
【DBA 警世录之习惯性命令---读书笔记】
👈【上一篇】 💖The Begin💖点点关注,收藏不迷路💖 【下一篇】👉 🔻【💣 话题引入:既然 DBA 这个职业如此危险,那么哪些习惯是 DBA 必须养成的呢&#x…...
Vue中如何进行状态持久化(LocalStorage、SessionStorage)
Vue中如何进行状态持久化(LocalStorage、SessionStorage)? 在Vue应用中,通常需要将一些状态进行持久化,以便在用户关闭浏览器或刷新页面后,仍能保留之前的状态。常见的持久化方式包括LocalStorage和Sessio…...
【30天熟悉Go语言】6 Go 复杂数据类型之指针
文章目录 一、前言二、数据类型总览三、指针1、特殊运算符& *2、内存角度来看指针3、使用指针修改数据4、指针使用的注意事项5、对比着看Java的引用类型 三、总结 一、前言 Go系列文章: GO开篇:手握Java走进Golang的世界2 Go开发环境搭建、Hello Wor…...
Linux内核使用红黑树的场景
进程调度队列 (Process Scheduling):内核需要对进程按照一定的调度策略进行排队,以便更好地利用 CPU 的时间片。因此,内核使用红黑树作为查找和管理进程调度队列的数据结构,以支持快速的查找、插入和删除操作。 文件系统 (File S…...
遗留的 AppSec 工具迷失在云端
随着应用程序开发步伐的加快,IT 和安全团队正在对旧的应用程序安全(AppSec) 工具失去信心。 根据 Backslash 对 300 名 CISO、AppSec 经理和工程师的调查,遗留工具无法跟上并陷入永远的追赶游戏。 影响是深远的,大多数组织都看到云原生 App…...
直流稳压电源与信号产生电路(模电速成)
目录 一、直流稳压电源 1、直流稳压电路 2、串联型稳压电路 3、集成稳压电路 二、信号产生电路 1、振荡电路 2、波形发生器 一、直流稳压电源 1、直流稳压电路 直流电源由 变压器、整流、滤波、稳压 四部分组成 整流:将交流变为直流 滤波:减小…...
0202性能分析-索引-MySQL
1 索引语法 创建索引 CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(index_column_name,...);Index_name:规范为idx_表名_字段名... 查看索引 SHOW INDEX FROM table_name;删除索引 DROP INDEX index_name ON table_name;按照下列要求,创建…...
Play wright自动化测试工具该如何更加完美地使用
目录 1.1 拦截网络请求 1.2 pytest 管理用例 1.3 PO模型 1.4 API 和 UI 自动化测试融合 1.5 数据驱动 1.6 动态挑选用例执行 1.6 Allure测试报告 1.7 持续集成 1.1 拦截网络请求 网络拦截: 无响应 pass 中止 route.abort("aborted") 放行 route…...
数据可视化学习笔记:Python实现汽车品牌销售量矩形树图
引言 本文将介绍如何使用 Python 和 Pyecharts 库创建一个汽车品牌销售量的矩形树图。我们将使用 Pandas 读取 CSV 文件数据,然后对数据进行处理、封装,最后将数据可视化为矩形树图。 准备工作 首先,我们需要先安装好相关库: PandasPyecharts可以使用 pip 命令进行安装:…...
【深蓝学院】手写VIO第3章--基于优化的 IMU 与视觉信息融合--作业
0. 题目 1. T1 T1.1 绘制阻尼因子曲线 将尝试次数和lambda保存为csv,绘制成曲线如下图 iter, lambda 1, 0.002000 2, 0.008000 3, 0.064000 4, 1.024000 5, 32.768000 6, 2097.152000 7, 699.050667 8, 1398.101333 9, 5592.405333 10, 1864.135111 11, 1242.7567…...
企业级信息系统开发讲课笔记4.11 Spring Boot中Spring MVC的整合支持
文章目录 零、学习目标一、Spring MVC 自动配置(一)自动配置概述(二)Spring Boot整合Spring MVC 的自动化配置功能特性 二、Spring MVC 功能拓展实现(一)创建Spring Boot项目 - SpringMvcDemo2021ÿ…...
chatgpt赋能python:Python安装EGG——一个简单的指南
Python安装EGG——一个简单的指南 如果你使用Python有一段时间了,你可能会遇到需要安装扩展包(Package)的情况。在Python中,这些扩展包的文件格式通常是.egg(Easy Installable GZip)。在本文中,…...
Web前端-React学习
React基础 React 概述 React 是一个用于构建用户界面的JavaScript库。 用户界面: HTML页面(前端) React主要用来写HTML页面, 或构建Web应用 如果从MVC的角度来看,React仅仅是视图层(V),也就…...
【Rust项目实战】sensleak,扫描 Git 仓库中的敏感信息
github仓库:https://github.com/open-rust-initiative/sensleak-rs Rust是一门神奇的编程语言,它提供了内存安全、零成本抽象、并发安全等特性,使开发人员能够编写高性能、高抽象和安全的代码。 这是我用rust开发的第一个工作,希望…...
手机能用的网站/内部优化
信号处理 信号处理是指信号的表示,变换和运算以及提取它们所包含的信息。如我们可以分开两个或多个混在一起的信号,或者增强信号中某些成分的参数。 信号处理基础 信号分为数字信号和模拟信号,在计算机中连续信号只能让信号的离散时间间隔…...
佛山专业的网站建设公司/百度竞价app
前言 Centos 7.9测试尚未发现bug 脚本 查找/home/jack/Desktop/test目录下中的所有文件,如果该文件包含simv字符串,则以绿色打印该文件名,并以默认颜色(黑色)打印包含simv的这一行内容 #!/usr/bin/env bash #SELFD…...
公安内网网站建设方案/京津冀协同发展
背景描述 由于想快速在服务器上部署一下spring boot的web应用,因此使用了java直接启动spring boot内置tomcat的方式来构建服务,实际上这也是spring boot的一个很大的亮点。 但是接着就遇到了一个很有意思的问题,在项目中使用了Thymeleaf作为模…...
网站建设和管理是教什么/百度视频免费高清影视
1,关于ace admin ace admin 是一个非常好的后台系统ui。 集成了很多的好东西。非常的方便开发后天系统,而且能很漂亮。 上面有一堆的例子。非常的漂亮。 http://ace.jeka.by/ 之前还是收费的。后来在github 上面放了一个项目。 但是没有源码。是压缩…...
vue做的网站大全/seo专员工资一般多少
实现一个通讯录;通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址提供方法:1.添加联系人信息2.删除指定联系人信息3.查找指定联系人信息4.修改指定联系人信息5.显示所有联系人信息6.清空所有联系…...
梅州网站制作/网站设计报价方案
“云”概念在今年被炒得很热。不管什么会,如果没有“云”,都不好意思跟人打招呼;在IT圈子里,如果一个没有“云”的会议,那不叫“会”议,至少不是一个够档次的会。广告词不是说,“高度决定视野,角…...