-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 105 KB
/
content.json
1
{"posts":[{"title":"IDEA插件之HTTP接口快速检索【RestfulTool】","text":"MAC系统推荐快捷键【定制:⌥ + ⌘ + N】 介绍一套 Restful 服务开发辅助工具集: 提供了一个 Services Tree 的显示窗口; 点击 URL 直接跳转到对应的方法定义; 一个简单的 Http 请求工具; 支持 Spring 体系 (Spring MVC / Spring Boot); 支持 Navigate -> Request Service 搜索 Mapping; 使用效果 Services Tree显示显示系统中所有的HTTP接口列表,点击接口可以跳转到接口定义。 URL快速检索跳转可以使用快捷键快速调出检索窗口,输入关键字进行模糊匹配,当项目是多模块多工程同时存在时,可以方便快捷区分定位接口。 HTTP工具一个简单的HTTP调用工具,因为太过简陋一般情况下用不着,不过可以用起来的一点是当选择对应接口时能快速生成对应请求参数,如下图。 配置一般不需要进行配置,使用默认配置即可。 总结总体来说这块插件是比较轻量级的,对我来说最大的用途就是能快速检索定位HTTP接口,大家如果有更好用的插件可以分享出来哈。","link":"/2023/03/27/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8BHTTP%E6%8E%A5%E5%8F%A3%E5%BF%AB%E9%80%9F%E6%A3%80%E7%B4%A2%E3%80%90RestfulTool%E3%80%91/"},{"title":"IDEA插件之依赖快捷搜索【Maven Search】","text":"MAC系统推荐快捷键【默认:Shift + CMD + M】 介绍快速查找maven依赖,定制模糊查找算法。支持查找全网类。注:该功能需要连接网络。所有数据来源于源码阅读网。 使用 搜索 复制 基于目标类搜索基于目标类搜索依赖包,定制化选取依赖包,可能会发现更多有意思的组件哦。 使用感想一般企业大部分依赖都是比较固定的,在开发过程中可能需要个别依赖包,使用此插件查看还是比较方便的,同时查看某个包当前最新的版本也是一种快捷方式,往往一个小工具能大大提升开发体验,后续好插件继续分享。","link":"/2023/01/31/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E4%BE%9D%E8%B5%96%E5%BF%AB%E6%8D%B7%E6%90%9C%E7%B4%A2%E3%80%90Maven%20Search%E3%80%91/"},{"title":"IDEA插件之好看的暗黑主题【GitHub Theme】","text":"介绍尽可能恢复GitHub主题,保持颜色易于区分,对比度适当,令人愉快的视觉享受。适用了多款主题插件的暗黑主题,最终还是使用本插件的主题,看着确实比较享受,在IDEA的新UI中的Dark主题也是这种配色。 配置配置比较简单,和IDEA主题配置融合。 效果 原装暗黑主题 插件暗黑主题文章效果可能不太明显,下载插件应用后效果还是比较明显。","link":"/2023/01/24/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E5%A5%BD%E7%9C%8B%E7%9A%84%E6%9A%97%E9%BB%91%E4%B8%BB%E9%A2%98%E3%80%90GitHub%20Theme%E3%80%91/"},{"title":"IDEA插件之彩虹括号【Rainbow Brackets】","text":"收费版本:Rainbow Brackets免费版本:Rainbow Brackets Lite 介绍一款可以将 (圆括号) [方括号] {花括号} <尖括号> 用不同颜色标记出来, 方便使用者快速识别代码层次, 提高开发效率!支持的语言:Java、Scala、Clojure、Kotlin、Python、Haskell、Agda、Rust、JavaScript、TypeScript、Erlang、Go、Groovy、Ruby、Elixir、ObjectiveC、PHP、HTML、XML、SQL、Apex语言、c#、Dart、Pug/Jade、Bash、Vue.js、c# Razor Pages、GLSL(OpenGL材质语言)、Go模板、c++、C… 使用 括号高亮上图能看到文件所有括号都添加了颜色,临近的括号颜色各不相同。 高亮选中代码块MAC快捷键【⌘ + 鼠标右键】途中绿色和紫色部分展示效果,能够更加清晰的看到当前范围。 暗淡未选中代码块MAC快捷键【⌥ + 鼠标右键】选中部分原样展示,未选中部分暗淡灰色展示,到这里大家脑海里已经有了使用场景了吧。 配置 配置比较简单大家自行使用体验哈! 使用感想在上边的例子中可能括号层级比较少,没有太大的触感,在工作中往往会出现层层嵌套的括号,快速定位括号位置,在无形中提高了开发效率,我是在第一次使用后就再也丢不掉了。","link":"/2023/02/10/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E5%BD%A9%E8%99%B9%E6%8B%AC%E5%8F%B7%E3%80%90Rainbow%20Brackets%E3%80%91/"},{"title":"IDEA插件之自动化生成注释【Easy Javadoc】","text":"MAC系统推荐快捷键【CMD + \\】 介绍能帮助开发者快速生成类、方法、属性等中文的javadoc/kdoc,此插件能快速生成注释,大多内容是没问题的,但是也会出现生成中文注释不符合预期的情况,需要人工进行修正,总体来看人工修正工作量比较小。 使用直接使用快捷键生成对应的注释。 类 方法 属性 配置生成内容存在不符合预期的情况,可定制化进行配置,使生成注释更加准确。插件包含Javadoc和Kdoc配置,以下以Javadoc为例。 Class Template Method Template Field Template","link":"/2023/01/24/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E8%87%AA%E5%8A%A8%E5%8C%96%E7%94%9F%E6%88%90%E6%B3%A8%E9%87%8A%E3%80%90Easy%20Javadoc%E3%80%91/"},{"title":"IDEA插件之驼峰转换【String Manipulation】","text":"MAC系统推荐快捷键【定制:⌃ + ⌥ + ⌘ + P】 介绍还在为大量需要转换的驼峰格式烦恼吗,有了这款插件,从此驼峰格式不再烦恼,😂 当然这款插件不仅仅能转换驼峰,还包含很多其他格式,如下: Toggle: SCREAMING_SNAKE_CASE / camelCase Toggle: snake_case / camelCase Toggle: kebab-case / snake_case Toggle: kebab-case / camelCase Toggle: dot.case / camelCase Toggle: PascalCase / camelCase Toggle: lowercase words / camelCase Toggle: First word capitalized / camelCase Toggle: Capitalized Words / camelCase To camelCase To snake_case To kebab-case To PascalCase To SCREAMING_SNAKE_CASE To Capitalized_Snake_Case Capitalize To lower case To UPPER CASE 配置可以调整转换格式条目的顺序,在选择格式化时更快匹配目标格式,也可以添加新的Action自定义多个格式化方式。 自定义Action自定义Action,添加快捷键,配置适合自己的格式化操作。 使用 右键调出这里能看到比较多的转换方式,但是根据菜单来转换,展开比较麻烦,效率不高,直接通过快捷键比较直接快速。 快捷键转换⌃ + ⌥ + ⌘ + P 直接使用快捷键爽歪歪。 使用感想在工作中使用频率还是比较高的,特别是从某个地方CV过来的数据,需要批量转换格式的时候,一键完成转换,极大提高效率,小小插件,快乐工作每一天。","link":"/2023/03/23/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E9%A9%BC%E5%B3%B0%E8%BD%AC%E6%8D%A2%E3%80%90String%20Manipulation%E3%80%91/"},{"title":"Java8 Stream 提高编码效率,早点下班","text":"编程中操作集合数据是非常频繁的,使用Java8 中的Stream对集合处理,结合Lambda函数式编程能极大的简化代码,合理的使用Stream能提高代码可读性,另一方面从Java8面世以来Stream API经过了无数项目的实践考验,其稳定性和性能自不必说,网上有很多相关的性能测试案例可以查阅参考,如果有人对你说:Lambda 可读性不好,维护成本高等一些问题,你大可放心,请一定看下最后的注意点。 1. Stream 创建Stream的创建方式比较多,接下来介绍几种常用的方式,以下Lists使用的google guava的API,直接上代码: 12345678910111213// 方式1:Stream.of以及其他的静态方法,测试常使用Stream<String> stream1 = Stream.of("A", "B");// 方式2:Collection方式,常见如(List、Set)Stream<String> stream2 = Lists.newArrayList("A", "B").stream();Stream<String> stream3 = Sets.newHashSet("A", "B").stream();// 方式3:数组方式Stream<String> stream4 = Arrays.stream(new String[]{"A", "B"});// 方式4:通过API接口创建,文件API等Stream<String> stream5 = Files.lines(Paths.get("/file.text"));// 方式5:创建基本数据类型对应的Stream,如:IntStream、LongStream、DoubleStreamIntStream stream6 = Arrays.stream(new int[] { 1, 2, 3 });// 方式6:通过Stream.builder创建Stream<Object> stream7 = Stream.builder().add("A").build(); 以上创建方式方式2、方式3比较常用,其中方式3也可以使用parallelStream创建并行流,其他的方式可以通过parallel方法转换为并行流,在数据量较大时提高数据处理效率,如下: 1234// 直接使用parallelStream创建Stream<String> stream1 = Lists.newArrayList("A", "B").parallelStream();// 使用parallel转化普通流为并行流Stream<String> stream2 = Arrays.stream(new String[]{"A", "B"}).parallel(); 2. Stream 中间操作Stream.map将原数据处理后生成新的数据,其中mapToInt、mapToLong、mapToDouble方法可直接转换为IntStream、LongStream、DoubleStream(用的比较少,大家可自行查找) 123456// 原数据添加后缀-NList<String> result1 = Lists.newArrayList("A") .stream().map(item -> item + "-N").collect(Collectors.toList());// 原字符串转化为数组List<String[]> result2 = Lists.newArrayList("A") .stream().map(item -> new String[]{item}).collect(Collectors.toList()); Stream.flatMap合并多个Stream为一个Stream,经常用在合并多个List数据 1234List<String> result = Lists.newArrayList( Lists.newArrayList("A"), Lists.newArrayList("B")).stream().flatMap(Collection::stream).collect(Collectors.toList()); Stream.filter元素过滤,可替代循环中的if判断条件,参数为逻辑表达式 12List<String> result = Lists.newArrayList("A", "B") .stream().filter("A"::equals).collect(Collectors.toList()); Stream.distinct元素去重复,一般用在简单数据类型,如果是对象可以利用TreeSet去重示例如下 12345678// 简单数据类型去重List<String> result1 = Lists.newArrayList("A", "A", "B") .stream().distinct().collect(Collectors.toList());// 对象数据去重List<Demo> result2 = Lists.newArrayList(new Demo()).stream().collect( Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(comparing(Demo::getName))), ArrayList::new)); 12345@Dataclass Demo { private String name; private String age;} Stream.peek只进行数据处理,不改变原数据类型,和map的区别就是peek接受一个无返回值的操作,一般用于修改对象内部元素 12List<Demo> result = Lists.newArrayList(new Demo()) .stream().peek(item -> item.setName("A")).collect(Collectors.toList()); Stream.sorted对数据进行排序,支持正序和倒序,并且支持对象类型数据排序 123456// 简单数据类型排序List<String> result1 = Lists.newArrayList("A", "B") .stream().sorted().collect(Collectors.toList());// 对象类型根据某个属性排序,默认正序,倒序使用reversed方法List<Demo> result2 = Lists.newArrayList(new Demo()) .stream().sorted(Comparator.comparing(Demo::getName).reversed()).collect(Collectors.toList()); Stream.limit限制最终输出数据的数量,截取流中的元素,默认不进行截取 12List<String> result1 = Lists.newArrayList("A", "B") .stream().limit(1).collect(Collectors.toList()); Stream.skip跳过前多少个元素,和limit类似,limit是截取流达到限制数量立刻返回流 12List<String> result = Lists.newArrayList("A", "B") .stream().skip(1).collect(Collectors.toList()); 3. Stream 终止操作collect收集流数据,常用:Collectors.toList(收集为List)、Collectors.joining(收集拼接为String) 1234// 收集数据为ListList<String> result1 = Lists.newArrayList("A", "B").stream().collect(Collectors.toList());// 收集数据为String,默认无分隔符,可以使用带参数的joining方法指定分隔符String result2 = Lists.newArrayList("A", "B").stream().collect(Collectors.joining()); reduce数据聚合为一个值,数据转化为单值后,计算得出一个最终值,这里已累加为例 1BigDecimal result = Lists.newArrayList(BigDecimal.valueOf(1), BigDecimal.valueOf(2)).stream().reduce(BigDecimal.ZERO, BigDecimal::add); allMatch、anyMatch、noneMatch 123456// 所有元素都大于1,返回trueboolean result1 = Lists.newArrayList(1, 2, 3, 4).stream().allMatch(item -> item > 1);// 任意元素大于1,返回trueboolean result2 = Lists.newArrayList(1, 2, 3, 4).stream().anyMatch(item -> item > 1);// 没有元素大于1,返回trueboolean result3 = Lists.newArrayList(1, 2, 3, 4).stream().noneMatch(item -> item > 1); count统计数据数量值 1long result1 = Lists.newArrayList(1, 2, 3, 4).stream().count(); findAny、findFirst如果存在数据,都返回一条,区别是在并行处理中,findAny匹配到数据就返回,findFirst需要等所有数据处理完成返回第一条,所以在并行处理中findAny效率更高 1234// 获取任意一个及时返回Integer result1 = Lists.newArrayList(1, 2, 3, 4).stream().findAny().get();// 所有元素执行完成返回第一条Integer result12= Lists.newArrayList(1, 2, 3, 4).parallelStream().findFirst().get(); forEach、forEachOrdered遍历所有元素,比如输出操作,有了forEach为什么还需要forEachOrdered呢,主要是在并行执行中,元素执行是没有顺序的,forEachOrdered能将结果按照顺序输出 1234// 输出所有元素Lists.newArrayList(1, 2, 3, 4).stream().forEach(System.out::println);// 顺序输出Lists.newArrayList(1, 2, 3, 4).parallelStream().forEachOrdered(System.out::println); max、min获取流中元素最大和最小的值,以下举例最大值得获取,最小值同理 1234// 简单数据类型Integer result = Lists.newArrayList(1, 2, 3, 4).stream().max(Integer::compare).get();// 比较对象中的属性,获取最大的记录Demo result = Lists.newArrayList(new Demo()).stream().max(comparing(Demo::getAge)).get(); 4. Stream 注意点在使用并行流进行处理时,一定需要收集最终数据,否则可能会丢失数据,比如使用collect或者reduce收集数据,也就是说使用了collect和reduce才能使用parallelStream,此时整个流处理是线程安全的。","link":"/2023/03/29/Java/Java8%20Stream%20%E6%8F%90%E9%AB%98%E7%BC%96%E7%A0%81%E6%95%88%E7%8E%87%EF%BC%8C%E6%97%A9%E7%82%B9%E4%B8%8B%E7%8F%AD/"},{"title":"IDEA插件之输入法自动切换【Smart Input Source】","text":"MAC系统推荐快捷键针对输入切换无需快捷键,但是在某些场景下比如Git Diff的时候可能存在自动跳转到源文件的情况,这种时候需要手动关闭自动切换功能,给作者提了个建议对这种场景进行优化。建议使用的快捷键,C代表关闭,O代表打开。 介绍 解决什么问题对于母语为中文的开发者,写代码过程中经常需要在中/英输入法之间进行切换,而且由于不清楚当前处于哪种输入状态,有时输入到一半发现输入法错了,删除后重新输入,严重影响了编码效率。还有在IdeaVim命令模式时必须使用英文输入法,由于不清楚当前处于哪种输入状态,而在IdeaVim命令模式下误用中文输入法,导致效率严重降低。其实,在哪种情况需要使用哪种输入法是可以明确的,既然这样就可以让IDE帮助我们自动切换输入法。 解决方案该插件核心功能可以根据输入位置的上下文智能分析当前处于什么场景应该使用哪种输入法并自动切换,而且还可以通过光标的颜色来提醒当前是什么输入法,关注官方博客了解更多特性。插件能够智能分析出十余种场景,根据不同场景自动切换输入法,详见插件设置页面。 如果识别当前场景为注释,则会自动切换为中文输入法。 如果识别当前场景为IdeaVim命令模式,则会自动切换为英文输入法。 配置无特殊需求使用默认配置即可。 基础配置 Java场景配置 使用 编码区自动切换英文输入 注释区自动切换中文输入 快捷键控制开关使用上文推荐的快捷键控制自动切换,如果不想设置快捷键方式也可以点击菜单功能进行控制如: 使用感想专注编码时自动切换输入法确实省事,把这些重复性的操作交给计算机自动控制,看到这款插件的时候,心里想为啥自己就没想到开发这样一款插件呢,真的是只要有需求就有对应的产品,合理利用工具,进一步解放生产力。","link":"/2023/01/27/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E8%BE%93%E5%85%A5%E6%B3%95%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%E3%80%90Smart%20Input%20Source%E3%80%91/"},{"title":"基于MybatisGenerator一键生成工程代码,重复性工作交给它准没错","text":"现在大多数的项目都是分多层结构,经典的如遵循MVC规范(Model-View-Controller),如果按照DDD领域模型设计可能会划分更多层,每一层需要创建多个类似模式的类文件和内容,包括类名、注释、属性、方法等,基于数据模型生成代码的插件和工具有很多,比如mybatis-plus、mybatis-generator、mybatisx等,当然市面上也有许多代码自动生成的产品,这些代码生成方式大部分都是生成固定文件结构,但是大多公司一般有自己的一套框架结构或者重新设计的分层结构,这个时候就需要自定义代码生成文件格式,包括生成文件位置和内容格式,今天为大家带来基于mybatis-generator插件的方式实现自定义代码结构,更好的适配现有代码工程。 基础配置基于插件基本功能生成的代码,包括Do.java、Example.java、Mapper.java、Mapper.xml文件,其中生成内容没有对应的注释信息,或者配置生成的配置信息不够人性化,基本无用。 插件配置12345678910111213141516171819202122232425262728293031<plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.2</version> <dependencies> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency> </dependencies> <configuration> <!-- 输出详细信息 --> <verbose>true</verbose> <!-- 覆盖生成的类文件 --> <overwrite>true</overwrite> <!-- 定义配置文件 --> <configurationFile>${basedir}/src/main/resources/generator-configuration.xml</configurationFile> </configuration> </plugin></plugins> 配置Maven插件,可以比较容易的触发生成代码。 配置文件12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration> <!-- 设置生成的文件适用于哪个Mybatis 版本 --> <context id="default" targetRuntime="MyBatis3"> <!-- 生成RowBounds方法 --> <plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"/> <!-- 覆盖XML Mapper文件,POM文件中配置的是Class文件覆盖 --> <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/> <!-- 旨在创建class时,对注释进行控制 --> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自动生成的注释 true:是 false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!-- jdbc的数据库连接 --> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/code_gen?useSSL=false" userId="root" password="123456"/> <!-- 非必须,类型处理器,在数据库类型和java类型之间的转换控制,默认情况下数据库中的decimal,bigint在Java对应是sql下的BigDecimal类 --> <javaTypeResolver> <!-- 使用常用的基本类型代替sql包下的引用类型 --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成的实体类所在的包 --> <javaModelGenerator targetPackage="com.example.codegen.domain" targetProject="src/main/java"> <!-- 是否允许子包 --> <property name="enableSubPackages" value="true"/> <!-- 是否清理从数据库中查询出的字符串左右两边的空白字符 --> <property name="trimStrings" value="false"/> </javaModelGenerator> <!-- 生成的mapper xml文件的包和位置 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <!-- 针对数据库的一个配置,是否把schema作为字包名 --> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- 生成的mapper class文件的包和位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.codegen.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <!-- 表配置 --> <table tableName="system_users" domainObjectName="SystemUsersDo"/> </context></generatorConfiguration> 配置注释信息写的比较清楚,这里给出部分配置信息,能够满足大部分需求,如有特殊需求可以参考 官方文档。 效果展示**生成代码总览**,具体生成内容介于文章内容就不做展示,大家可以实际配置生成。 准备工作进入正题配置我们的自定义插件配置,基于MybatisGenerator提供的上下文信息可以方便的获取到元数据信息,自定义插件有两种解决方案: 在项目工程中定义插件,执行生成代码可以动态加载对应的插件; 基于MybatisGenerator核心包修改,不侵入项目工程,可以方便的分享给其他人使用; 当然,本篇文章主要介绍基于MybatisGenerator核心包修改的方式,简单在GitHub上边搜索mybatis-generator-core发现魔改项目还挺多,接下来实际进行操作。 拉取核心包可以从GitHub直接拉取魔改的仓库,或者直接下载源码解压,我这里直接从仓库中找到源码并解压,mybatis-generator-core-1.4.2-sources。 导入工程 将源码包移动到/src/main/java中; 从/META-INF/maven/org.mybatis.generator/mybatis-generator-core中将pom.xml文件复制一份出来放到根目录下并删除部分内容; 修改坐标,groupId或者artifactId都是可以的;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.local.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.0.0</version> <name>mybatis-generator-core</name> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.6</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.20.0</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <version>1.10.13</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>5.9.2</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.9.2</version> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.24.2</version> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.7.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.github.javaparser</groupId> <artifactId>javaparser-core</artifactId> <version>3.25.0</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>1.8.10</version> <scope>test</scope> </dependency> </dependencies></project> 其中依赖版本从parent获取,配置完成后移除parent,配置完成后注意执行mvn clean install操作,将包install到仓库中。 工程依赖自定义插件依赖自定义的工程包,groupId和artifactId可以自行修改,我这里未变更,仅修改版本号为1.0.0,执行生成代码查看效果,我这里执行无任何变化,需要注意的是一定需要修改坐标,不然可能遇到执行出现null的情况,目测是插件执行过程中验证了某些信息。 自定义插件说了一堆前置条件,终于到了文章的重点,自定义插件逻辑实现,本篇文章主要介绍定制化Mapper.java、实体注释优化、Service.java生成逻辑,可以参考生成更多内容,如Controller.java、Manager.java等等,生成逻辑都是相似的几乎可以CV CV CV,一个分层结构插件可能存在比较多的上下文,为了方便按照层拆分插件数量。 JavaMapperPlugin插件:主要定制化基础插件功能生成的Do.java、Mapper.java文件; ServicePluginc插件:生成Model.java、Convertor.java、Service.java、ServiceImpl.java文件; 添加配置123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration> <!-- 设置生成的文件适用于哪个Mybatis 版本 --> <context id="default" targetRuntime="MyBatis3"> <!-- 自定义全局属性,根据实际情况进行修改 --> <property name="author" value="reboot"/> <property name="baseProject" value="/Users/xx/Codes/IdeaProjects/Demos/code-gen"/> <!-- 生成RowBounds方法 --> <plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"/> <!-- 覆盖XML Mapper文件,POM文件中配置的是Class文件覆盖 --> <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/> <!-- 自定义插件,Mapper生成、扩展添加注释、使用通用接口 --> <plugin type="org.mybatis.generator.plugins.custom.JavaMapperPlugin"/> <!-- 自定义插件,Service生成 --> <plugin type="org.mybatis.generator.plugins.custom.ServicePlugin"/> <!-- 旨在创建class时,对注释进行控制 --> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自动生成的注释 true:是 false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!-- jdbc的数据库连接 --> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/code_gen?useSSL=false" userId="root" password="123456"/> <!-- 非必须,类型处理器,在数据库类型和java类型之间的转换控制,默认情况下数据库中的decimal,bigint在Java对应是sql下的BigDecimal类 --> <javaTypeResolver> <!-- 使用常用的基本类型代替sql包下的引用类型 --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成的实体类所在的包 --> <javaModelGenerator targetPackage="com.example.codegen.domain" targetProject="src/main/java"> <!-- 是否允许子包 --> <property name="enableSubPackages" value="true"/> <!-- 是否清理从数据库中查询出的字符串左右两边的空白字符 --> <property name="trimStrings" value="false"/> </javaModelGenerator> <!-- 生成的mapper xml文件的包和位置 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <!-- 针对数据库的一个配置,是否把schema作为字包名 --> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- 生成的mapper class文件的包和位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.codegen.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <!-- 表配置 --> <table tableName="system_users" domainObjectName="SystemUsersDo"> <property name="comment" value="系统用户"/> <generatedKey column="id" sqlStatement="Mysql" identity="true"/> </table> </context></generatorConfiguration> 修改点如下: 1234567891011121314<!-- 自定义全局属性,根据实际情况进行修改 --><property name="author" value="reboot"/><property name="baseProject" value="/Users/xx/Codes/IdeaProjects/Demos/code-gen"/><!-- 自定义插件,Mapper生成、扩展添加注释、使用通用接口 --><plugin type="org.mybatis.generator.plugins.custom.JavaMapperPlugin"/><!-- 自定义插件,Service生成 --><plugin type="org.mybatis.generator.plugins.custom.ServicePlugin"/><!-- 表配置,其中comment属性为自定义添加 --><table tableName="system_users" domainObjectName="SystemUsersDo"> <property name="comment" value="系统用户"/> <generatedKey column="id" sqlStatement="Mysql" identity="true"/></table> JavaMapperPlugin插件123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596package org.mybatis.generator.plugins.custom;import org.mybatis.generator.api.GeneratedJavaFile;import org.mybatis.generator.api.IntrospectedTable;import org.mybatis.generator.api.PluginAdapter;import org.mybatis.generator.api.dom.DefaultJavaFormatter;import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;import org.mybatis.generator.api.dom.java.Interface;import org.mybatis.generator.api.dom.java.JavaVisibility;import org.mybatis.generator.api.dom.java.TopLevelClass;import java.util.ArrayList;import java.util.List;/** * JavaMapper插件 * * @author reboot */public class JavaMapperPlugin extends PluginAdapter { private List<String> warnings; private String tableComment; private String author; private String baseProject; private static final String MAPPER_BASE = "/src/main/java"; private static final String MAPPER_PACKAGE = "com.example.codegen.mapper"; @Override public boolean validate(List<String> warnings) { this.warnings = warnings; return true; } @Override public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) { tableComment = introspectedTable.getTableConfigurationProperty("comment"); author = introspectedTable.getContext().getProperty("author"); baseProject = introspectedTable.getContext().getProperty("baseProject"); List<GeneratedJavaFile> javaFiles = new ArrayList<>(); // DO javaFiles.add(generateDoFile(introspectedTable)); // Mapper javaFiles.add(generateMapperFile(introspectedTable)); return javaFiles; } /** * 生成DO文件 * * @param introspectedTable 表信息 * @return {@link GeneratedJavaFile} */ private GeneratedJavaFile generateDoFile(IntrospectedTable introspectedTable) { String fullDoName = introspectedTable.getBaseRecordType(); String doName = PluginUtils.getClassName(fullDoName); PluginUtils.fileExistCheck(fullDoName, baseProject + MAPPER_BASE, warnings); TopLevelClass doTopLevelClass = PluginUtils.generateEntity(introspectedTable, this.context, fullDoName, PluginUtils.classDoc(tableComment + "数据模型", doName, author)); return new GeneratedJavaFile(doTopLevelClass, baseProject + MAPPER_BASE, new DefaultJavaFormatter()); } /** * 生成Mapper文件 * * @param introspectedTable 表信息 * @return {@link GeneratedJavaFile} */ private GeneratedJavaFile generateMapperFile(IntrospectedTable introspectedTable) { String fullDoName = introspectedTable.getBaseRecordType(); String doName = PluginUtils.getClassName(fullDoName); String mapperName = doName + "Mapper"; String fullMapperName = MAPPER_PACKAGE + "." + mapperName; String exampleName = doName + "Example"; String fullExampleName = fullDoName + "Example"; PluginUtils.fileExistCheck(fullMapperName, baseProject + MAPPER_BASE, warnings); Interface baseMapperInterface = new Interface(new FullyQualifiedJavaType(fullMapperName)); baseMapperInterface.addFileCommentLine(PluginUtils.fileComment()); baseMapperInterface.setVisibility(JavaVisibility.PUBLIC); baseMapperInterface.addJavaDocLine(PluginUtils.classDoc(tableComment + "Mapper", mapperName, author)); baseMapperInterface.addSuperInterface(new FullyQualifiedJavaType("BaseMapper<" + doName + "," + exampleName + ">")); baseMapperInterface.addImportedType(new FullyQualifiedJavaType("com.example.codegen.mapper.BaseMapper")); baseMapperInterface.addImportedType(new FullyQualifiedJavaType(fullDoName)); baseMapperInterface.addImportedType(new FullyQualifiedJavaType(fullExampleName)); return new GeneratedJavaFile(baseMapperInterface, baseProject + MAPPER_BASE, new DefaultJavaFormatter()); }} ServicePluginc插件1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283package org.mybatis.generator.plugins.custom;import org.mybatis.generator.api.GeneratedJavaFile;import org.mybatis.generator.api.IntrospectedTable;import org.mybatis.generator.api.PluginAdapter;import org.mybatis.generator.api.dom.DefaultJavaFormatter;import org.mybatis.generator.api.dom.java.Field;import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;import org.mybatis.generator.api.dom.java.JavaVisibility;import org.mybatis.generator.api.dom.java.TopLevelClass;import org.mybatis.generator.internal.util.JavaBeansUtil;import java.util.ArrayList;import java.util.List;/** * Service插件 * * @author reboot */public class ServicePlugin extends PluginAdapter { private List<String> warnings; private String tableComment; private String author; private String baseProject; private static final String SERVICE_BASE = "/src/main/java"; private static final String SERVICE_PACKAGE = "com.example.codegen.service"; private static final String MAPPER_PACKAGE = "com.example.codegen.mapper"; @Override public boolean validate(List<String> warnings) { this.warnings = warnings; return true; } @Override public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) { tableComment = introspectedTable.getTableConfigurationProperty("comment"); author = introspectedTable.getContext().getProperty("author"); baseProject = introspectedTable.getContext().getProperty("baseProject"); List<GeneratedJavaFile> javaFiles = new ArrayList<>(); // Service javaFiles.add(generateServiceFile(introspectedTable)); return javaFiles; } /** * 生成Service文件 * * @param introspectedTable 表信息 * @return {@link GeneratedJavaFile} */ private GeneratedJavaFile generateServiceFile(IntrospectedTable introspectedTable) { String fullDoName = introspectedTable.getBaseRecordType(); String doName = PluginUtils.getClassName(fullDoName); String serviceName = doName.replace("Do", "Service"); String fullServiceName = SERVICE_PACKAGE + "." + serviceName; String mapperName = doName + "Mapper"; String fullMapperName = MAPPER_PACKAGE + "." + mapperName; PluginUtils.fileExistCheck(fullServiceName, baseProject + SERVICE_PACKAGE, warnings); TopLevelClass serviceTopLevelClass = new TopLevelClass(fullServiceName); serviceTopLevelClass.addFileCommentLine(PluginUtils.fileComment()); serviceTopLevelClass.setVisibility(JavaVisibility.PUBLIC); serviceTopLevelClass.addJavaDocLine(PluginUtils.classDoc(tableComment + "领域服务实现", serviceName, author)); serviceTopLevelClass.addAnnotation("@Component"); Field mapperField = new Field(JavaBeansUtil.getValidPropertyName(mapperName), new FullyQualifiedJavaType(mapperName)); mapperField.setVisibility(JavaVisibility.PUBLIC); mapperField.addAnnotation("@Autowired"); serviceTopLevelClass.addField(mapperField); serviceTopLevelClass.addImportedType("org.springframework.stereotype.Component"); serviceTopLevelClass.addImportedType("org.springframework.beans.factory.annotation.Autowired"); serviceTopLevelClass.addImportedType(fullMapperName); return new GeneratedJavaFile(serviceTopLevelClass, baseProject + SERVICE_BASE, new DefaultJavaFormatter()); }} 抽取通用工具123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115package org.mybatis.generator.plugins.custom;import org.mybatis.generator.api.IntrospectedColumn;import org.mybatis.generator.api.IntrospectedTable;import org.mybatis.generator.api.dom.java.Field;import org.mybatis.generator.api.dom.java.JavaVisibility;import org.mybatis.generator.api.dom.java.TopLevelClass;import org.mybatis.generator.config.Context;import org.mybatis.generator.internal.util.JavaBeansUtil;import java.io.File;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.List;/** * 插件工具类 * * @author reboot */public class PluginUtils { /** * 文件存在性检查 * * @param fullName 全名 * @param basePath 基本路径 * @param warnings 警告 */ public static void fileExistCheck(String fullName, String basePath, List<String> warnings) { String path = String.join(File.separator, basePath, fullName.replace(".", File.separator), ".java"); if (new File(path).exists()) { warnings.add("java file" + fullName + " already exists in " + basePath + " and will be overridden."); } } /** * 获取类名 * * @param recordType 记录类型 * @return {@link String} */ public static String getClassName(String recordType) { return recordType.substring(recordType.lastIndexOf(".") + 1); } /** * 文件注释,自行实现 * * @return {@link String} */ public static String fileComment() { return "/* 文件头 2023 */"; } /** * 类注释 * * @param remark 备注 * @param className 类名 * @param author 作者 * @return {@link String} */ public static String classDoc(String remark, String className, String author) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"); StringBuilder javaDoc = new StringBuilder(); javaDoc.append("/**\\n"); javaDoc.append(" * " + remark + "\\n"); javaDoc.append(" *\\n"); javaDoc.append(" * @author " + author + "\\n"); javaDoc.append(" * @version " + className + ".java, v0.1 " + LocalDateTime.now().format(dateTimeFormatter) + " " + author + "\\n"); javaDoc.append(" */"); return javaDoc.toString(); } /** * 属性注释 * * @param remark 备注 * @return {@link String} */ public static String fieldDoc(String remark) { StringBuilder fieldDoc = new StringBuilder(); fieldDoc.append("/**\\n"); fieldDoc.append("\\t * " + remark); fieldDoc.append("\\n"); fieldDoc.append("\\t */"); return fieldDoc.toString(); } /** * 生成实体 * * @param introspectedTable 表信息 * @param context 上下文 * @param fullName 全限定名 * @param javaDoc java注释 * @return {@link TopLevelClass} */ public static TopLevelClass generateEntity(IntrospectedTable introspectedTable, Context context, String fullName, String javaDoc) { TopLevelClass topLevelClass = new TopLevelClass(fullName); topLevelClass.addFileCommentLine(fileComment()); topLevelClass.setVisibility(JavaVisibility.PUBLIC); topLevelClass.addAnnotation("@Data"); topLevelClass.addImportedType("lombok.Data"); topLevelClass.addJavaDocLine(javaDoc); for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) { Field field = JavaBeansUtil.getJavaBeansField(introspectedColumn, context, introspectedTable); field.addJavaDocLine(fieldDoc(introspectedColumn.getRemarks())); topLevelClass.addField(field); topLevelClass.addImportedType(field.getType()); } return topLevelClass; }} 验证效果 SystemUsersDo\u0000.java SystemUsersDoMapper\u0000.java SystemUsersService\u0000.javaService这里仅仅举个例子,我写的插件生成内容比较简单,可以根据实际情况生成。 总结虽说不建议重复造轮子,但是轮子没有那么好,就只好基于轮子造轮子了,上边的写法可能不是最好的,但是能满足项目工程总体框架结构,一般的后台系统生成基本的CRUD功能还是非常方便的,基于这种方式几乎项目中相同模式的代码都可以生成,不要让基础的功能浪费大量时间。","link":"/2023/04/05/Java/%E5%9F%BA%E4%BA%8EMybatisGenerator%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E5%B7%A5%E7%A8%8B%E4%BB%A3%E7%A0%81%EF%BC%8C%E9%87%8D%E5%A4%8D%E6%80%A7%E5%B7%A5%E4%BD%9C%E4%BA%A4%E7%BB%99%E5%AE%83%E5%87%86%E6%B2%A1%E9%94%99/"},{"title":"Java没有扩展方法?是你没有找对方法","text":"扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。对于用 C# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法没有明显的差异。 支持扩展方法的语言其实比较多的编程语言都支持了扩展方法,如C#、Visual Basic、Kotlin等,但我们的Java语言就是迟迟不支持,在JDK9中开始支持以jmod方式扩展java功能,JDK16承诺给出动态库调用方案,但是作为JDK8的钉子户的我们如果也想使用扩展方法,就得另寻他路了。 C#1234567891011121314/// 扩展方法public static class ExpandMethod { /// 两个数相加 public static int Sum(this int num,int num2) { return num + num2; }}public class Program { static void Main(string[] args) { /// 调用位置 Console.WriteLine(3.Sum(2)); }} Visual Basic123456789101112131415161718192021222324Imports System.Runtime.CompilerServicesModule Module3 Sub Main() Dim ex As New ExampleClass ' 调用位置 ex.ExampleMethod("Extension method") End Sub Class ExampleClass ' Define an instance method named ExampleMethod. Public Sub ExampleMethod() Console.WriteLine("Instance method") End Sub End Class <Extension()> Sub ExampleMethod(ByVal ec As ExampleClass, ByVal stringParameter As String) Console.WriteLine(stringParameter) End Sub End Module Kotlin12345678910111213// 扩展函数(本类中扩展方法)class Test1 { var name: String = "boyi.chen"}fun Test1.temp() { println("增加扩展函数,打印扩展类的属性name=${this.name}")}fun main(args: Array<String>) { // 调用位置 Test1().temp()} 主角登场Java8本身不支持扩展方法,但我们可以通过插件的方式实现扩展方法,用起来跟直接使用扩展方法一样一样的,Lombok就是其中的一款插件。 Lombok @ExtensionMethod通过Lombok @ExtensionMethod注解,程序编译期间帮我们生成直接调用的静态方法,当然IDEA插件能提供更好的支持,下边看下具体的例子。 1234567891011121314151617181920212223242526272829/** * lombok测试 * * @author reboot */@ExtensionMethod(StringUtil.class)public class LombokTest { public static void main(String[] args) { System.out.println("".isBlank()); } /** * 字符串工具 * * @author reboot */ public static class StringUtil { /** * 字符串判空 * * @param targetStr 目标str * @return boolean */ public static boolean isBlank(String targetStr) { return targetStr == null || "".equals(targetStr); } }} 编译后的内容可以看到方法已经从 “”.isBlank() 转换为 LombokTest.StringUtil.isBlank(“”)\u0000,Lombok也正是通过这种方式提供给我们扩展方法的语法糖,真的好甜。 Manifold这里就不具体介绍了,感兴趣的朋友可以看这篇文章 Java 缺失的特性:扩展方法 作者写的还是比较全面的。 总结扩展方法能够使我们的代码看起来更加简洁,但是对于曾经未接触过的同学,可能第一次碰到会比较懵,所以要适当使用哦,上边提到了两种扩展方法的实现方式,如果项目中本来就引入了Lombok建议直接使用@ExtensionMethod比较好,不要再引入其他插件,这样会增加项目接手和熟悉的成本,今天就讲到这里,希望对阅读本文章的你有所帮助。","link":"/2023/03/24/Java/Java%E6%B2%A1%E6%9C%89%E6%89%A9%E5%B1%95%E6%96%B9%E6%B3%95%EF%BC%9F%E6%98%AF%E4%BD%A0%E6%B2%A1%E6%9C%89%E6%89%BE%E5%AF%B9%E6%96%B9%E6%B3%95/"},{"title":"IDEA插件之注释快捷展示【Show Comment】","text":"介绍 在结构树显示 文档注释; 在行末尾显示 文档注释; 输入 doc / docc 等生成 /** */; json 字段注释从 xxx.json.tsv 读取; json 字典注释从 键名.tsv 读取; 支持 “xx-类全名或简名.json” 文档注释与跳转到字段; 支持 从配置文件获取外部注释用于文件夹、资源、COBOL 等; 修改配置:设置 -> 工具 -> // Show Comment Global/Project; 使用自动显示注释,在阅读源码时比较实用,能迅速了解代码表达的意思,当然排除注释不真实的情况哈,这里列举几个实例。 结构树显示注释 行末尾显示注释 配置 Show Comment Global可针对注释的展现形式进行全局配置,如文本颜色、显示行数、前缀等。 Show Comment Project也可对项目注释是否展示进行配置,配置包含正则和排除正则表达式。 使用感想在对项目不太熟悉的情况下,对于快速了解项目,梳理业务逻辑,此插件还是比较实用的,提升工程熟悉进度。","link":"/2023/01/31/IDEA/IDEA%E6%8F%92%E4%BB%B6%E4%B9%8B%E6%B3%A8%E9%87%8A%E5%BF%AB%E6%8D%B7%E5%B1%95%E7%A4%BA%E3%80%90Show%20Comment%E3%80%91/"},{"title":"神器MapStruct,性能爆棚的实体转换 _ 复制工具","text":"Java项目中实体转换无处不在,当实体字段较多或者大批量的进行复制时,通过手工setter/getter显得太LOW,同时兼备高性能要求情况下,MapStruct完全完全能够胜任。官方解释,MapStruct是一个代码生成器,它基于约定优于配置的方法,极大地简化了Java bean类型之间映射的实现。生成的映射代码使用普通方法调用,因此快速、类型安全且易于理解。因为MapStruct是在编译期间生成setter/getter方法,实际运行时就是直接调用setter/getter,效率会非常高。 优点 MapStruct编译期生成映射代码,所以可以在编译时暴露映射错误的代码,让错误提前暴露; 因为使用setter/getter方式,而非反射方式,所以可以更快的执行效率; 可以实现深拷贝,自动类型转换,如枚举转换; 进行自定义的映射,多种映射方式,下边具体说明; 性能对比 对比对象 10个对象复制1次 1万个对象复制1次 100万个对象复制1次 100万个对象复制5次 MapStruct 0ms 3ms 96ms 281ms Hutools的BeanUtil 23ms 102ms 1734ms 8316ms Spring的BeanUtils 2ms 47ms 726ms 3676ms Apache的BeanUtils 20ms 156ms 10658ms 52355ms Apache的PropertyUtils 5ms 68ms 6767ms 30694ms 使用 依赖1234567891011121314151617181920212223242526272829<!-- MapStruct核心,包含了一些必要的注解--><dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <annotationProcessorPaths> <!-- MapStruct编译,注解处理器,根据注解自动生成Mapper的实现 --> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins></build> 定义转换接口123456789101112131415161718192021222324252627282930313233343536373839404142434445/** * 测试接口 * * @author reboot */@Mapperpublic interface OrderConvertor { /** * 实例 */ OrderConvertor INSTANCE = Mappers.getMapper(OrderConvertor.class); /** * OrderDo -> OrderModel * * @param orderDo 订单实体 * @return {@link OrderModel} */ OrderModel toModel(OrderDo orderDo); /** * OrderDo -> OrderModel * * @param orderDos 订单实体 * @return {@link OrderModel} */ List<OrderModel> toModel(List<OrderDo> orderDos); /** * OrderModel -> OrderDo * * @param orderModel 订单模型 * @return {@link OrderDo} */ OrderDo toDo(OrderModel orderModel); /** * OrderModel -> OrderDo * * @param orderModels 订单模型 * @return {@link OrderDo} */ List<OrderDo> toDo(List<OrderModel> orderModels);} 编译结果MapStruct会自动生成对应接口的实现,并自动完成属性映射关系,List会自动进行批量处理。 调用1234567891011121314151617181920/** * 订单服务 * * @author reboot */@Servicepublic class OrderService { /** * 获取订单列表 * * @return {@link List}<{@link OrderModel}> */ public List<OrderModel> getOrderList() { // 获取数据库数据DO List<OrderDo> result = selectOrderList(); // 参数转换 return OrderConvertor.INSTANCE.toModel(result); }} 插件上边的使用方式虽然能够正常使用,但是在一些属性配置映射上和提示上,如果使用插件能够提升使用体验,IDEA中可以直接安装Mapstruct Support插件,当然Eclipse也有对应的插件。 特性 突出显示目标属性和源属性。将目标属性和源属性转到声明的setter / getter中; 错误和快速修复: 缺少@Mapper或@MapperConfig注解检查; 快速修复未映射的目标属性,添加未映射目标属性和忽略未映射目标属性; 其他用法更加详细的内容可以查看官方文档,发布文章时最新版本是 MapStruct 1.5.3.Final.html。 基础映射12345678910@Mapperpublic interface CarMapper { @Mapping(target = "manufacturer", source = "make") @Mapping(target = "seatCount", source = "numberOfSeats") CarDto carToCarDto(Car car); @Mapping(target = "fullName", source = "name") PersonDto personToPersonDto(Person person);} target表示目标属性名,source表示源属性名,一般在目标属性和源属性不同时使用,相同的属性名会自动进行映射。 映射器添加自定义方法1234567891011@Mapperpublic interface CarMapper { @Mapping(...) ... CarDto carToCarDto(Car car); default PersonDto personToPersonDto(Person person) { //hand-written mapping logic }} 自定义方法personToPersonDto并实现,在生成的实现类中会进行覆盖使用。 多个源参数映射1234567891011@Mapperpublic interface AddressMapper { @Mapping(target = "description", source = "person.description") @Mapping(target = "houseNumber", source = "address.houseNo") DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address); @Mapping(target = "description", source = "person.description") @Mapping(target = "houseNumber", source = "hn") DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);} 存在多个源参数,使用参数名.属性名的方式进行表示,也可以直接使用基础类型的属性名称。 嵌套属性映射到当前目标12345678@Mapper public interface CustomerMapper { @Mapping( target = "name", source = "record.name" ) @Mapping( target = ".", source = "record" ) @Mapping( target = ".", source = "account" ) Customer customerDtoToCustomer(CustomerDto customerDto); } 当源参数中存在对象属性,可以手动进行映射,或者直接使用”.”的方式将对象中的属性全部映射到当前目标对象。 表达式方式1234567891011@Mapperpublic interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); @Mapping( target = "timeAndFormat", expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )" ) Target sourceToTarget(Source s);} 支持使用java代码块进行转换,一般可以将静态方法处理的字段放到这里。 更新现有实例12345@Mapperpublic interface CarMapper { void updateCarFromDto(CarDto carDto, @MappingTarget Car car);} @MappingTarget源参数,编译时会将carDto参数中的属性映射到car参数中。 Map映射123456@Mapperpublic interface CustomerMapper { @Mapping(target = "name", source = "customerName") Customer toCustomer(Map<String, String> map);} 直接将map中的key进行映射。 更多用法还有更多其他用法,比如: 支持映射定义的public属性; 支持映射参数Builder模式; 使用注入方式引入转换器; 数据类型字段转换,如枚举、日期,支持日期格式化,支持数字类型格式化,具体可以看 Implicit type conversions; 集合类型自动转换; 转换Stream; …… 总结MapStruct还有很多其他高阶特性,限于篇幅文章仅仅列举部分示例,有兴趣的同学可以查看对应文档试试。使用适当的工具有效提高编程效率,在使用工具过程中我们也了解其实现原理,不断提高自身。后边有时间也把MapStruct实现原理拿出来讲讲,跟大家一起学习进步!","link":"/2023/03/26/Java/%E7%A5%9E%E5%99%A8MapStruct%EF%BC%8C%E6%80%A7%E8%83%BD%E7%88%86%E6%A3%9A%E7%9A%84%E5%AE%9E%E4%BD%93%E8%BD%AC%E6%8D%A2%20_%20%E5%A4%8D%E5%88%B6%E5%B7%A5%E5%85%B7/"},{"title":"编译期动态替换三方包中的Class文件","text":"背景最近做业务时遇到一个问题,客户想在底层数据添加一个字段,只能乖乖的添加表字段、实体添加对应属性,一切都在预期中进行这,但是这个工程是经过二开的,展示层实体没法直接添加,于是想当然继承实体扩展字段,没想到顶层一堆Request、Response,如果一个一个进行扩展马也得累死,于是就思考有没有简便的方法仅对目标实体进行操作来完成字段添加的方法。 思考过程在Java中要在类中添加字段属性,除了显示编码外,还有一种技术就是编译期间动态修改,比如Lombok、Mapstruct等都是在编译期动态生成代码,提高编码效率,所以我也考虑通过这种方式编译期添加目标字段属性,百度了一通没有合适的方式动态添加,但是手写通过字节码注入一定是可以实现的,想想成本还是有点高,赶紧转换思路,既然不能动态插入字段,那能不能直接替换目标类呢?一想到这就有戏,在Java中加载类是通过类加载器进行加载的,有了依据后赶紧接着百度,果不然让我发现一种方式,通过maven插件的方式实现,客官接着往下看。一般情况下不建议用这么hack的方式哈,尽量保持三方包的新鲜度,避免未来升级导致的兼容性问题。 主角出场主角:maven-dependency-plugin这仅仅是处理的一种方式,大家如果有更好的处理方式,可以放到评论区,我们一起讨论,互相学习进步。 实现原理通过配置maven-dependency-plugin,可以将我们指定的dependency解压到项目的class目录中,设置不覆盖本地项目相同class文件(类的全限定名相同),就实现了本地文件替换三方jar中类文件的目的了。在Java应用中,如果存在多个同名类,最终只会加载一个目标类,到底会加载哪个同名类是又类加载器的双亲委派机制决定的,先请求父类加载器加载,父类无法加载回到应用程序加载器,应用程序无法加载就会到类路径下即class目录中加载,如果仍然不存在会到依赖中进行加载。基于以上原理,实现类文件覆盖就有了依据,那么接下来具体实践演示下。 使用这里我使用commons-lang3\u0000举例。 第一步:配置Maven插件1234567891011121314151617181920212223242526272829<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.1.2</version> <executions> <execution> <!-- unpack任务标识符,unpack是将依赖从仓库中解压到指定目录 --> <id>unpack</id> <!-- unpack任务默认执行阶段 --> <phase>generate-sources</phase> <goals> <!-- 目标功能:unpack --> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <!-- 设置为false,依赖解压到目录时不会进行覆盖,设置为true则会覆盖 --> <overWrite>false</overWrite> <!-- 目标class文件输出目录 --> <outputDirectory>${project.build.directory}/classes</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions></plugin> 第二步:编译工程这一步还没有定义目标类,暂时仅是将目标三方包的类放到了class目录下,标红的位置是即将要进行修改的位置。 第三步:添加目标类 包名和目标类所在包名完全一致; 类名保持一致; 第四步:重新编译工程至此已经能够看到效果了,整个方式过程也比较简单,去掉中间的编译过程,总共两步。 总结这种Hack的方式在业务编码中建议少用,通过上边的方式虽然能解决问题,但同时也引入了一些副作用,一方面相当于依赖包引入两份,另一方面当依赖包升级时可能存在疏漏。看看学习学习,多一种解决方式多一条路,希望大家每天编码顺顺利,我就先溜了!","link":"/2023/03/15/Java/%E7%BC%96%E8%AF%91%E6%9C%9F%E5%8A%A8%E6%80%81%E6%9B%BF%E6%8D%A2%E4%B8%89%E6%96%B9%E5%8C%85%E4%B8%AD%E7%9A%84Class%E6%96%87%E4%BB%B6/"},{"title":"接口异步调用,接口耗时减少的可不是一点点","text":"随着业务发展,底层数据量越来越大,业务逻辑也日趋复杂化,某些接口耗时也越来越长,这时候接口就需要进行性能优化了,当然性能优化主要跟业务相关涉及改造点可能各不相同,这里就来介绍异步调用多个接口减少响应时间。 适用条件 调用多个独立的接口,接口间无相互依赖关系 非耗时最大的接口占总耗时比重较大 优化前调用方式优化前的代码按照顺序调用方式: 123456789101112131415161718192021222324252627282930313233343536373839404142434445import lombok.extern.slf4j.Slf4j;@Slf4jpublic class DemoTest { public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); int processA = new InterfaceA().process(); int processB = new InterfaceB().process(); int result = processA + processB; log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } }} 执行结果: 12321:40:17.603 [main] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms21:40:19.612 [main] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2001ms21:40:19.613 [main] INFO DemoTest - 执行结果:2 耗时:4018 优化后调用方式优化后的代码按照异步调用方式: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768import cn.hutool.core.thread.ThreadFactoryBuilder;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.Future;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;@Slf4jpublic class DemoTest { private static ThreadPoolExecutor pool = new ThreadPoolExecutor( 5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000), ThreadFactoryBuilder.create().setNamePrefix("线程名称-").build() ); public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); List<Future<Integer>> futures = new ArrayList<>(2); List<Integer> results = new ArrayList<>(2); futures.add(pool.submit(() -> new InterfaceA().process())); futures.add(pool.submit(() -> new InterfaceB().process())); for (Future<Integer> item : futures) { results.add(item.get()); } int result = results.get(0) + results.get(1); log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } }} 执行结果: 12322:03:43.180 [线程名称-1] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2004ms22:03:43.180 [线程名称-0] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2004ms22:03:43.190 [main] INFO DemoTest - 执行结果:2 耗时:2020 此方式还可以结合CompletionService可实现异步任务和执行结果分离,大家可以自行搜索实践 强大的CompletableFuture JDK1.812345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364import com.google.common.collect.Lists;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CompletableFuture;@Slf4jpublic class DemoTest { public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); CompletableFuture<Integer> interfaceFuturesA = CompletableFuture.supplyAsync(() -> new InterfaceA().process()); CompletableFuture<Integer> interfaceFuturesB = CompletableFuture.supplyAsync(() -> new InterfaceB().process()); CompletableFuture<List<Integer>> future = CompletableFuture .allOf(interfaceFuturesA, interfaceFuturesB) .thenApply((none) -> { List<Integer> dataList = new ArrayList<>(2); try { dataList.add(interfaceFuturesA.get()); dataList.add(interfaceFuturesB.get()); } catch (Exception e) { log.error("执行异常"); } return dataList; }).exceptionally(e -> Lists.newArrayList()); int result = future.get().get(0) + future.get().get(1); log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime); } @Slf4j public final static class InterfaceA { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); } log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } } @Slf4j public final static class InterfaceB { Integer result = 1; public int process() { long beginTime = System.currentTimeMillis(); try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); } log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime); return result; } }} 执行结果: 12322:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2005ms22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms22:31:44.831 [main] INFO DemoTest - 执行结果:2 耗时:2027 优化时注意点 使用线程池防止内存溢出风险 执行结果容器可自行根据需要设置 接口粒度可根据实际业务情况组合和拆分","link":"/2022/04/29/Java/%E6%8E%A5%E5%8F%A3%E5%BC%82%E6%AD%A5%E8%B0%83%E7%94%A8%EF%BC%8C%E6%8E%A5%E5%8F%A3%E8%80%97%E6%97%B6%E5%87%8F%E5%B0%91%E7%9A%84%E5%8F%AF%E4%B8%8D%E6%98%AF%E4%B8%80%E7%82%B9%E7%82%B9/"},{"title":"Linux下如何快速搜索大文件?","text":"工作中经常使用Linux进行部署应用服务,处理日志文件过大问题,最常见的是日志文件打满服务器影响服务器性能,以往我们需要手动查看可能的目录同时清理过的大文件,本篇文章就来介绍如何快速搜索系统下大文件的方法,提高工作效率。find 12# 搜索/目录下所有文件在1024K以上的文件find / -type f -size +10240k du 12# 查看当前目录下文件大小,倒序输出排名前十du -sh * | sort -rh | head -10 详细信息可以查看 【 菜鸟教程-Linux find 命令 】 【 菜鸟教程-Linux du 命令 】","link":"/2021/05/20/Linux/Linux%E4%B8%8B%E5%A6%82%E4%BD%95%E5%BF%AB%E9%80%9F%E6%90%9C%E7%B4%A2%E5%A4%A7%E6%96%87%E4%BB%B6%EF%BC%9F/"},{"title":"十分钟安装部署大模型ChatGML-6B","text":"近期大模型可谓是如火如荼,按耐不住也想手动安装部署大模型,近距离接触大模型,废话不多说直接开始安装部署。 部署机器准备 可以在某某云申请GPU服务器,模型会跑的更快; 本地电脑配置尚佳也可以用来跑模型,配置不同响应效果略有区别; 安装环境目前绝大多数模型都是使用python语言,这里我们使用conda管理python环境。 安装miniconda可以从这里获取对应版本的安装程序:Latest Miniconda Installer Links,下载完成以后执行命令,这里我已Linux为例。 1bash Miniconda3-latest-Linux-x86_64.sh 按照提示进行安装,完成安装后配置~/.bashrc文件,添加如下一行配置。 1conda_dir=/root/miniconda3 执行如下命令使配置生效,之后你会看到命令行前出现base,代表conda生效。 1source ~/.bashrc 创建虚拟环境使用虚拟环境管理python依赖,防止环境被污染,当然如果仅仅部署一套程序,完全可以使用base环境,甚至可以直接使用基础python环境,习惯使用conda了。 123456# 创建虚拟环境ChatGLM-6Bconda create -n ChatGLM-6B python=3.11# 启用ChatGLM-6B虚拟环境conda activate ChatGLM-6B# 退出虚拟环境conda deactivate 安装Git如果没有git环境需要安装,可以通过git –version进行检查。 123yum install git# 方便下载模型权重yum install git-lfs 下载资源大模型部署涉及的资源基本都是 模型代码+模型权重,ChatGLM-6B开源代码参考 https://github.com/THUDM/ChatGLM-6B,里边安装步骤其实比较详细,这里简单顺下。 下载模型代码1git clone https://github.com/THUDM/ChatGLM-6B.git 下载模型权重模型可以从HF进行下载,这里我下载量化模型int4为例。 1234# 下载模型相关基础小文件git clone https://huggingface.co/THUDM/chatglm-6b-int4# 下载lfs类型文件,包含模型权重文件git lfs pull 可能下载速度过慢,可以直接手动下载后将文件放到目录下即可。 部署模型ChatGLM-6B有多个实例程序,如:web_demo、cli_demo,这里通过web_demo部署页面UI程序,修改根目录下web_demo.py程序。 12345tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).half().cuda()# 添加server_name使外部浏览器能够访问,否则是回环地址demo.queue().launch(share=False, inbrowser=True, server_name='0.0.0.0') 将其中的THUDM/chatglm-6b修改为上方下载模型权重的路径即可,以上代码配置的是有GPU的机器,如果是其他环境可以参考官方文档支持。 运行模型1234# 前台运行程序python web_demo.py# 后台运行,实时显示日志nohup python -u web_demo.py > nohup.out 2>&1 & CPU运行1model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).float() MAC运行1model = AutoModel.from_pretrained("your local path", trust_remote_code=True).half().to('mps') mac运行如果遇到问题可以参考官方文档进行解决,https://github.com/THUDM/ChatGLM-6B#mac-部署 结果速览访问地址:http://127.0.0.1:7860/ 总结我是按量买的云服务,穷人真难,看着充值金额不断下降,心疼啊。本次带来大模型最为基础的部署指南,后续我会持续更新,包括大模型微调、大模型原理等内容,敬请期待哦。","link":"/2023/05/20/%E5%A4%A7%E6%A8%A1%E5%9E%8B/%E5%8D%81%E5%88%86%E9%92%9F%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E5%A4%A7%E6%A8%A1%E5%9E%8BChatGML-6B/"},{"title":"记一次Github仓库被Fork后删除的经历","text":"1.写在前面作为开发者,我们都比较了解Github,有时兴致冲冲的将项目放到Github上维护起来,还期待获得几个star,不经意可能将敏感数据或者文件push到云端,当发现需要删除的时候可能已经来不及了,仓库已经被其他用户fork了,因为fork的仓库我们是没法直接删除的,遇到这种情况不要慌,还是有办法解决的。一般这种情况要么是需要删除某些敏感文件或数据,要么是需要直接删除整个仓库,我们可以从下边几种方式进行处理,希望对有困难的兄弟有所帮助。 2.直接联系用户方式如果能直接联系到仓库拥有着,要求其删除是最便捷的方式了,但能联系上对方也是需要看运气的,毕竟很多 GitHub 用户是水军,在平台上并不活跃,总之试试总是好的,说不定成功了呢。 2.1通过Github用户信息最简单直接的方式就是通过Github用户所留的信息,如包含邮箱、社交渠道等信息,可以直接联系用户,当然大部分用户是不会留真实的信息的。 2.2通过提交代码是配置的邮箱信息用户在提交代码是一般会配置提交者用户名和邮箱号,这个是客户端配置的,一般也不太会是真实的信息,也只能靠运气试试看。 找到一条作者的提交记录 在提交记录的url地址添加后缀.patch 2.3通过向作者的仓库提交issue找到作者活动比较多的自有项目,提交issue告知事项并等待对方答复或联系自己,这种方式只能看作者心情和品行了。 2.4通过作者曾经提交的issue进行回复这种情况和2.3类似,看作者心情。 找到作者最近活动记录 回复相关issue 3.通过官方途径进行维权如果通过以上途径均无法联系到对方,或者短时间内比较着急并未获得对方回复,这种情况下可以通过官方途径进行申诉,由官方强制进行下架处理,这种方式需要申请人填写的资料相对较多,并且是全英文的内容,毕竟Github是面向世界的托管平台,这时候借助翻译软件会省心不少。虽然官方途径比较麻烦,但是官方处理效率还是蛮高的,我这边提交申请后很快得到回复,不到一周整个流程顺利结束。对于Github内容删除政策,可以参考中文版文档,可能不是最新的但是大体内容是一致的:https://docs.github.com/zh/site-policy/content-removal-policies/submitting-content-removal-requests英语过关的同学可以直接上原版链接:https://docs.github.com/en/site-policy/content-removal-policies/submitting-content-removal-requests 3.1私人删除部分内容和文件私人信息删除申请入口:https://support.github.com/contact/private-information 3.2删除整个仓库DMCA下架申请入口:https://support.github.com/contact/dmca-takedown如果有公函或者其他附件证,能明仓库所属和侵权行为,附件内容最好英文翻译并连同原版发送,通过邮件再次提交,建议发送完整内容(问题+附件),邮箱地址:[email protected] 4.总结遇到数据泄露或者侵权事情的时候,确实比较心累,来自自身的压力或者其他方面的压力,这个时候需要头脑冷静的处理问题,将处理的流程梳理出来心里会踏实点,寻求他人的帮助也是一种途经,总之能解决问题就是圆满。这里我将自己经历的Github数据泄露处理流程分享出来,希望能帮助到遇到困难的同志们,加油!最后如果是通过官方途径提交申诉的方式,一定要填写的清楚些,描述清楚,不然官方会通过邮件进行确认比较耗费时间。","link":"/2021/05/12/%E5%88%86%E4%BA%AB/%E8%AE%B0%E4%B8%80%E6%AC%A1Github%E4%BB%93%E5%BA%93%E8%A2%ABFork%E5%90%8E%E5%88%A0%E9%99%A4%E7%9A%84%E7%BB%8F%E5%8E%86/"},{"title":"从头搭建我的博客网站","text":"不断的摄入也需要输出,才能看到相对成本,便于更好进步,搭建一个博客更好的输出。 1、选择静态博客模板框架因为我没有太多的功能需求,目前选择使用静态博客框架,目前市面上框架也很多,比较主流的如:Jekyll(Ruby语言) Octopress(基于Jekyll) Hexo(Node语言) Hugo(GO语言)等,详细信息大家可以搜索引擎,本文选择Hexo来搭建博客网站。 2、安装本地开发环境 安装Node.js 地址:https://nodejs.org/zh-cn/ 默认会安装NPM包管理器 查看Node版本和npm版本:node -v/npm -v 安装最新版本就行 3、安装Hexo12345678npm install -g cnpm --registry=https://registry.npm.taobao.org 全局安装cnpmcnpm install -g hexo-cli 安装Hexo框架生成器mkdir blog 创建博客目录cd blog 进入目录hexo init 初始化博客生成器hexo s/hexo server 启动本地博客hexo n "新建博客" 新建博客文件hexo g 打包成静态文件,默认在public目录下 4、添加主题全局配置将以下配置添加至博客根目录下的_config.yml文件最后 123456789101112131415161718jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true 5、接入评论功能Hexo默认支持的评论接口在themes/yilia/_config.yml配置文件中,多说、网易云跟帖、畅言、Disqus、Gitment,本文使用的是畅言接入。 6、上传静态文件到云服务器如果有云服务器(腾讯云,阿里云,百度云,京东云等)将静态博客文件上传到指定目录,使用nginx代理静态文件,就大功告成啦! 7、个性化修改 所有的个性化主题配置基本都在themes/yilia/_config.yml下,大家可以自行摸索,具体可以参考:https://github.com/litten/hexo-theme-yilia 去除畅言评论发表下方的广告:themes/yilia/layout/_partial/post/changyan.ejs文件结尾添加: 123456<style> .section-service-w { margin-top: -250px !important; transform: scale(0) !important; }</style> 最终效果如下: 截取文章部分内容作为摘要添加<!-- more -->至需要截取的Markdown文章相应的位置即可 分页设置如果当前博客数小于每页大小是不会展示分页组件的,分页配置通过Hexo配置文件进行设置","link":"/2021/05/12/%E5%8D%9A%E5%AE%A2/%E4%BB%8E%E5%A4%B4%E6%90%AD%E5%BB%BA%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99/"},{"title":"博客自动化部署","text":"经过部署自己的静态博客页面,我们已经可以发表文章到博客系统了,但是每次都需要编译、打包文件上传到云服务器,相同的流程能使用工具完成时最好的,接下来就结合git版本管理工具实现自动化部署流程,后续我们的操作就只有上传MD文件博客页面就能自动更新。 1、选择版本管理工具这里我们直接使用码云 ,速度相对较快,大家懂得,直接创建代码仓库将我们的博客代码push到远端,但是需要注意需忽略文件,如果使用idea可以下载.gitignore插件: 12345.idea*.imlnode_modulesoutdb.json 其中out是打包输出路径,可以从项目根目录_config.yml进行调整,db.json需要忽略,避免部署时产生冲突 2、云服务器安装运行环境 git下载 下载安装,或者通过yum进行安装 12345第一种:yum install git第二种:将下载后的二进制文件包解压,设置环境变量,可自行百度下载安装完成后查看版本git -version node下载 根据需要下载对应版本,本文下载Linux 二进制文件 (x64) 123456789解压压缩包tar -xvf node-v14.16.1-linux-x64.tar.xz重命名文件名mv node-v14.16.1-linux-x64 node14创建软连接,设置环境变量ln -s node14/bin/node /usr/bin/node查看版本node -vnpm -v 3、拉取代码并安装Hexo 拉取代码并手动部署 123456789101112拉取远程代码git clone https://gitee.com/代码仓库地址初始化node依赖包 npm install安装cnpmnpm install -g cnpm --registry=https://registry.npm.taobao.org通过cnpm安装hexocnpm install -g hexo-cli创建hexo软链,设置全局环境变量ln -s /export/app/kayla-blog/node_modules/hexo-cli/bin/hexo /usr/bin/hexo编译生成静态文件hexo g 设置用户名密码直接修改项目目录下.git/config,最后添加如下内容 12[credential] helper = store 4、创建自动化脚本如果以上步骤正常接下来就比较简单了,通过linux的cron定时执行脚本任务触发拉取最新博客内容和编译静态文件 创建cron任务 123456查看当前任务列表crontab -l编辑创建任务crontab -e表达式调用,每三分钟执行一次,执行hexo-g.sh结果写入hexo.out,注意:必须添加 2>&1 */3 * * * * /export/app/hexo-g.sh >> /export/app/hexo.out 2>&1 脚本内容hexo-g.sh 1234567891011121314#!/bin/bashsource /etc/profilesource ~/.bashrcecho "开始自动编译,当前时间:$(date "+%Y-%m-%d %H:%M:%S")"cd /export/app/blogecho "开始拉取gitee代码"git pullecho "代码拉取完成"echo "开始编译生成静态文件->out"hexo gecho "完成" 测试结果可能部署过程中会遇到一些坑,解决有困难的同学可以放到评论区,大家一起解决,相互交流学习 12345678910111213141516开始自动编译,当前时间:2021-05-04 07:51:01开始拉取gitee代码From https://gitee.com/xxx/blog1ecc028..980f12b master -> origin/masterUpdating 1ecc028..980f12bFast-forward...215\\232\\345\\256\\242\\347\\275\\221\\347\\253\\231.md" | 66 +++++++++++++---------1 file changed, 38 insertions(+), 28 deletions(-)代码拉取完成开始编译生成静态文件->outINFO Validating configINFO Start processingINFO Files loaded in 270 msINFO Generated: 2021/05/03/从头搭建我的博客网站/index.htmlINFO 1 files generated in 76 ms完成 5、发布博客到各大内容网站自己的博客被更多的人看到并应用才能真正体现它的价值,可以将Markdown格式的博客信息放到 博客园、CSDN、掘金、简书等内容网站。","link":"/2021/05/12/%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2/"},{"title":"MAC命令行工具","text":"现代命令行工具,不想记忆复杂的命令就来看看这些吧。 现代命令行工具1234567891011121314151617181920212223242526272829303132fish是功能齐全的命令行外壳程序(如 bash 或 zsh),既智能又友好。Fish 支持强大的功能,例如语法突出显示,自动建议和仅需工作的制表符补全,而无需学习或配置。fzffzf 是一款使用 GO 语言编写的交互式的命令行工具.fdfd 是find命令的替代品,用于文件名搜索.rgripgrep 是grep命令的替代品,用来搜索文件内容.exaexa 是ls命令的替代品,可以彩色输出目录内容,更容易辨识.batbat 是cat命令的替代品,输出文本文件的内容,并且带有cat所没有的代码高亮和行号.ncduncdu 是du命令的替代品,用来显示每个目录占用的大小.brootbroot 可以看作增强版的ls替代品,实际是一个终端里面的文件管理.tldr该命令可以显示一些命令的常见用法.macvimVim是一个高级文本编辑器,旨在提供事实上的Unix编辑器'Vi'的强大功能,具有更完整的功能集.jqjq 是一款命令行下处理 JSON 数据的工具. 参考文章Fish shell 入门教程:https://www.ruanyifeng.com/blog/2017/05/fish_shell.htmlModern Unix:https://github.com/ibraheemdev/modern-unix","link":"/2024/05/20/%E5%B7%A5%E5%85%B7/MAC%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7/"},{"title":"使用MAC进行软件开发","text":"今天来介绍一款Mac系统ORC识别软件Bob,相信ORC对大家来说都不陌生了,就是图片文字识别,日常生活中有不少场景需要从图片中读取文字内容,虽然Mac最新的系统已经自带图片ORC识别功能,但使用体验上还需要更上一层楼,废话不多说,直接进入正题。 介绍Bob官方介绍:Bob 是一款 macOS 平台 翻译 和 OCR 软件。详细介绍大家到GitHub搜索“Bob”就能看到,安装方式啥的照着抄就行了,个人感觉免费版本就够用了,当然要追求更好的体验的同志们可以用商店版。 使用我这边使用Bob主要还是用来做OCR,翻译功能用的不是很多,这里针对每一项功能大概演示下效果。 划词翻译需要选中目标词汇,点击功能菜单或者快捷键【⌥ + D】弹出翻译内容。 截图翻译框选(使用快捷键【⌥ + S】)图中的Bob直接进行翻译,并且识别到文字,可以直接复制内容,这个功能其实是使用最多的。 截图OCR快捷键:【⌥ + ⇧ + D】其他功能大家感兴趣可以自己尝试哦,整体上这块软件我使用频率还是蛮高的,作为程序员能省一步就是进步。 使用感想ORC已经非常成熟了,Bob确实能从一定程度上提升工作效率,随着AI技术的发展,作为程序员的我,对未来充满希望,但也有担忧,只有不断提升自身能力,利用更多的时间来做AI无法完成的事情,做有价值的事。","link":"/2023/02/16/%E5%B7%A5%E5%85%B7/Mac%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7%E4%B9%8BOCR%E8%AF%86%E5%88%AB%E3%80%90Bob%E3%80%91/"},{"title":"使用MAC进行软件开发","text":"作为一名程序员,我经历了从使用Windows、Ubuntu、MAC系统进行开发工作,最终我选择了MAC系统,原因主要有两个:软件运行流畅度、界面视觉享受高以下介绍使用MAC系统过程中,我常用的一些软件,浏览器插件相关可跳转至 好用的Google浏览器插件 1、包管理器:brewMAC系统使用比较好的包管理器,新系统没有预安装brew,需要自行安装,执行命令 1/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 2、软件下载网站和浏览器插件下载网站下方相关软件如果你不方便从官网进行下载可通过以下网站进行下载并安装,有兴趣的同学可以自行探索哦软件下载: App Store:https://www.apple.com/app-store/ 柠檬精选:https://lemon.qq.com/lab/ MacWk:https://www.macwk.com/ 浏览器插件下载: Google网上应用商店:https://chrome.google.com/webstore/category/extensions 极简插件:https://chrome.zzzmh.cn/ Crx4Chrome:https://www.crx4chrome.com/ Tampermonkey插件下载: GreasyFork:https://greasyfork.org/zh-CN Userscript.Zone Search:https://www.userscript.zone/ OpenUserJS:https://openuserjs.org/ 3、开发环境:git maven推荐使用上边的包管理器brew进行安装,安装成功后即可全局访问 123456默认的安装包路径/usr/local/Cellar/安装 gitbrew install git安装 mavenbrew install maven 4、开发相关工具 IntelliJ IDEA 使用Toolbox App安装,管理IDEA,推荐插件可以前往 IDEA插件提高工作效率 FinalShell 国产SSH客户端,支持文件传输,评价还不错 SwitchHosts 本地host管理工具 Visual Studio Code 我是直接当做文本编辑器用了,打开速度较快 Dash 文档管理工具,付费的,这里提供一个我自己买的license 点击下载 draw.io 免费的画图软件,如UML等 5、MAC系统辅助工具 腾讯柠檬 MAC上的电脑管家,简洁 超级右键 类似Windows右键功能的软件,需要去Mac App Store下载 pap.er 桌面壁纸,需要去App Store下载 Bob 平台翻译和OCR软件 MenubarX 将菜单栏变成浏览器 Alfred Mac效率神器","link":"/2021/05/12/%E5%B7%A5%E5%85%B7/%E4%BD%BF%E7%94%A8MAC%E8%BF%9B%E8%A1%8C%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91/"},{"title":"好用的Google浏览器插件","text":"好用的浏览器插件帮助我们高效的浏览网络资源,以下记录以作备用,下载链接可以跳转至 使用MAC进行软件开 Axure RP Extension for Chrome Chrome Better History 1Chrome Better History 比Chrome默认的历史记录查看更好用 crxMouse Chrome 1充分发掘鼠标的所有操作 功能包括:鼠标手势,超级拖曳,滚轮手势,摇杆手势,平滑滚动,标签页列表等 EverSync 1同步浏览器标签 Marinara: 番茄工作法 1番茄工作法(Pomodoro®)时间管理助理 Tampermonkey 广告终结者 1清除网页上的所有广告:浮动广告,购物广告,恶意弹窗,跟踪代码。让你浏览网页更快更清爽。广告终结者,你唯一需要的广告插件 掘金 1为程序员、设计师、产品经理每日发现优质内容 书签侧边栏 1在浏览器视图区左侧添加可调节的侧边栏管理您的书签 Tampermonkey 脚本 AC-baidu-重定向优化百度搜狗谷歌必应搜索_favicon_双列 12345671.繞過百度、搜狗、谷歌、好搜搜索結果中的自己的跳轉鏈接,直接訪問原始網頁-反正都能看懂 2.新增自定义网站拦截功能 3.添加Favicon显示 4.页面CSS 5.添加计数 6.开关选择以上功能 7.自动翻页功能 bilibili merged flv+mp4+ass+enhance 1bilibili/哔哩哔哩: 超清FLV下载,FLV合并,原生MP4下载,弹幕ASS下载,CC字幕转码ASS下载,AAC音频下载,MKV打包,播放体验增强,原生appsecret,不借助其他网站 Userscript+ : 显示当前网站所有可用的UserJS脚本 Jaeger 1显示当前网站的所有可用 UserJS(Tampermonkey)脚本 🔥持续更新🔥 CSDN广告完全过滤、人性化脚本优化:🆕 不用再登录了!让你体验令人惊喜的崭新CSDN 1⚡️拥有数项独家功能的最强CSDN脚本,不服比一比⚡️|🕶无需登录CSDN,获得比会员更佳的体验|🖥分辨率自适配,分屏不用滚动|💾超级预优化|🔖独家超级免会员|🏷独家原创文章免登录展开|🔌独家推荐内容自由开关|📠独家免登录复制|🔗独家防外链重定向|📝独家论坛未登录自动展开文章、评论|🌵全面净化|📈沉浸阅读|🧴净化剪贴板|📕作者信息文章顶部展示","link":"/2021/05/12/%E5%B7%A5%E5%85%B7/%E5%A5%BD%E7%94%A8%E7%9A%84Google%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6/"},{"title":"更好用的浏览器书签管理器Flash Copilot 闪记","text":"浏览器虽然自带书签管理器,但不好用,最近通过B站发现一款好用的插件,快速检索书签、浏览历史、当前窗口和标注,可以通过快捷键快速唤起,经过一段时间使用总体还是很好用的。 安装Google浏览器安装Flash Copilot,直接应用商店搜索安装即可,如果网络限制可以在文章最后获取。 配置使用Flash Copilot需要登录账号,注册一个账号即可,配置只有一个简单的快捷键配置界面,根据自身需求配置。 使用通过快捷键快速呼出弹框并选择对应页面。 参考无法直接安装插件的小伙伴可以直接下载插件包导入到Google内核的浏览器 国内镜像。","link":"/2024/05/19/%E5%B7%A5%E5%85%B7/%E6%9B%B4%E5%A5%BD%E7%94%A8%E7%9A%84%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B9%A6%E7%AD%BE%E7%AE%A1%E7%90%86%E5%99%A8Flash%20Copilot%20%E9%97%AA%E8%AE%B0/"},{"title":"单例模式-DCL","text":"铁子们有段时间没有更新了,最近忙着准备面试,准备过程中发现自己还需要积累的实在是太多太多,每每学到新东西的感觉真是美妙而又动力十足啊,继续伸直腰杆、努力前进。 单例模式-DCL双重检查判断,使用volatile关键字禁止指令重排,在多线程情况下创建安全的单例对象,直接上代码 123456789101112131415161718192021222324public class Instance { /** * volatile 禁止指令重排,按照代码执行顺序先赋值后创建对象 */ private volatile static Instance instance; private String instName; private Instance() { instName = "DCL"; } public static Instance getInstance() { if (instance == null) { synchronized (Instance.class) { if (instance == null) { instance = new Instance(); } } } return instance; }} 单例模式-内部类使用内部类构造单例对象,JVM保证单例 12345678910public class Instance { private static class InstanceObj { private static final Instance INSTANCE = new Instance(); } public static Instance getInstance() { return InstanceObj.INSTANCE; }}","link":"/2021/06/10/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F-DCL/"},{"title":"我的Java面试复习","text":"经过这段时间的面试复习,整理了不少资料文章,这里将我整理的知识点导图分享出来,仅供大家参考,欢迎多多建议。 原文地址(可以点击查看文章):https://zhimap.com","link":"/2022/04/29/%E9%9D%A2%E8%AF%95/%E6%88%91%E7%9A%84Java%E9%9D%A2%E8%AF%95%E5%A4%8D%E4%B9%A0/"},{"title":"好用的SDK版本管理工具SDKMAN","text":"作为一名Java后端开发人员,安装开发环境我们再熟悉不过了,如果有一款工具帮助我们自动安装环境,岂不是快哉,今天要介绍的就是一款后端SDK版本管理工具SDKMAN,客官请接好。 遇到的问题 换新电脑了,又要重新安装新环境,不同环境需要去各大网站下载、安装和配置; 临时换环境版本,本地验证,如maven、java的版本等; 程序本地验证,临时安装中间件程序,如MQ; 本地性能测试工具管理,如jmeter; 目前支持安装 activemqantasciidoctorjballerinabldbpipebtraceconcurnasconnor coursiercubacxfdetektdoctoolchainflinkgaidengcngrace gradlegradleprofilergrailsgroovygroovyservhadoophelidonhttp4kinfrastructor jarvizjavajbakejbangjettyjikkoujmcjmeterjoern jreleaserkarafkcctlkikobwebkotlinkscriptktxlayrry leiningenliquibasemavenmcsmicronautmulefdmvndmybatisneo4jmigrations pierrotpomcheckerquarkussbtscalascalaclischemacrawlerskeletalspark springbootsshoogrtaxitomcattoolkitvertxvisualvmwebtauznai 常用的工具都有的,如gradle、java、jmeter、maven等。 开始安装使用官方地址:https://sdkman.io/ 安装1curl -s "https://get.sdkman.io" | bash 命令行执行自动安装完成,接下来就可以直接使用了。 常用命令图中列出来了常用的命令,英文也写的比较清楚,这里我就不一一解释了,以下是我本地的效果。 sdk current java123(base) ➜ ~ sdk current java Using java version 8.0.412-zulu sdk current1234567(base) ➜ ~ sdk currentUsing:gradle: 6.9.4java: 8.0.412-zulumaven: 3.9.6 sdk list1234567891011121314151617181920212223242526272829303132333435================================================================================Available Candidates================================================================================q-quit /-search downj-down ?-search upk-up h-help--------------------------------------------------------------------------------Apache ActiveMQ (Classic) (5.17.1) https://activemq.apache.org/Apache ActiveMQ® is a popular open source, multi-protocol, Java-based messagebroker. It supports industry standard protocols so users get the benefits ofclient choices across a broad range of languages and platforms. Connect fromclients written in JavaScript, C, C++, Python, .Net, and more. Integrate yourmulti-platform applications using the ubiquitous AMQP protocol. Exchangemessages between your web applications using STOMP over websockets. Manage yourIoT devices using MQTT. Support your existing JMS infrastructure and beyond.ActiveMQ offers the power and flexibility to support any messaging use-case. $ sdk install activemq--------------------------------------------------------------------------------Ant (1.10.13) https://ant.apache.org/Apache Ant is a Java library and command-line tool whose mission is to driveprocesses described in build files as targets and extension points dependentupon each other. The main known usage of Ant is the build of Java applications.Ant supplies a number of built-in tasks allowing to compile, assemble, test andrun Java applications. Ant can also be used effectively to build non Javaapplications, for instance C or C++ applications. More generally, Ant can beused to pilot any type of process which can be described in terms of targets andtasks. $ sdk install ant--------------------------------------------------------------------------------下面还有很多! sdk list java12345678910111213141516171819202122232425262728================================================================================ Available Java Versions for macOS ARM 64bit ================================================================================ Vendor | Use | Version | Dist | Status | Identifier -------------------------------------------------------------------------------- Corretto | | 22.0.1 | amzn | | 22.0.1-amzn | | 21.0.3 | amzn | | 21.0.3-amzn | | 17.0.11 | amzn | | 17.0.11-amzn | | 11.0.23 | amzn | | 11.0.23-amzn | | 8.0.412 | amzn | | 8.0.412-amzn Gluon | | 22.1.0.1.r17 | gln | | 22.1.0.1.r17-gln | | 22.1.0.1.r11 | gln | | 22.1.0.1.r11-gln GraalVM CE | | 22.0.1 | graalce | | 22.0.1-graalce | | 21.0.2 | graalce | | 21.0.2-graalce | | 17.0.9 | graalce | | 17.0.9-graalce GraalVM Oracle| | 23.ea.10 | graal | | 23.ea.10-graal | | 23.ea.9 | graal | | 23.ea.9-graal | | 22.0.1 | graal | | 22.0.1-graal | | 21.0.3 | graal | | 21.0.3-graal | | 17.0.11 | graal | | 17.0.11-graal Java.net | | 23.ea.25 | open | | 23.ea.25-open | | 23.ea.24 | open | | 23.ea.24-open | | 22 | open | | 22-open | | 21.0.2 | open | | 21.0.2-open JetBrains | | 21.0.3 | jbr | | 21.0.3-jbr | | 17.0.11 | jbr | | 17.0.11-jbr | | 11.0.14.1 | jbr | | 11.0.14.1-jbr下面还有很多! 使用感受谁用谁知道哈哈!","link":"/2024/06/08/%E5%B7%A5%E5%85%B7/%E5%A5%BD%E7%94%A8%E7%9A%84SDK%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7SDKMAN/"},{"title":"仅一条命令安装大模型的工具Ollama","text":"接着上一篇《十分钟安装部署大模型ChatGML-6B》我们在机器上一步步安装ChatGML-6B大模型,这次我们来介绍一款更加方便的大模型安装工具Ollama,无需安装任何环境仅需一个命令即可将大模型安装到本机。 官网https://ollama.com/官方提供mac、linux和windows平台安装包,安装软件好处是能及时升级新功能,软件下载后按照提示安装即可。Ollama目前支持如下大模型: Model Parameters Size Download Llama 3 8B 4.7GB ollama run llama3 Llama 3 70B 40GB ollama run llama3:70b Phi 3 Mini 3.8B 2.3GB ollama run phi3 Phi 3 Medium 14B 7.9GB ollama run phi3:medium Gemma 2 9B 5.5GB ollama run gemma2 Gemma 2 27B 16GB ollama run gemma2:27b Mistral 7B 4.1GB ollama run mistral Moondream 2 1.4B 829MB ollama run moondream Neural Chat 7B 4.1GB ollama run neural-chat Starling 7B 4.1GB ollama run starling-lm Code Llama 7B 3.8GB ollama run codellama Llama 2 Uncensored 7B 3.8GB ollama run llama2-uncensored LLaVA 7B 4.5GB ollama run llava Solar 10.7B 6.1GB ollama run solar 一键安装ollama软件安装完成后,打开命令行直接执行以下命令即可安装llama3大模型。 1ollama run llama3 效果1234567891011121314151617181920212223242526272829303132➜ ollama run llama3>>> 你好😊 你好!我很高兴见到你!如何可以帮助你今天? 🤔>>> 你是谁😊 我是 LLaMA,一个由 MetaAI 开发的人工智能语言模型。我可以理解和生成人类语言,可以与您进行对话、回答问题、提供信息和建议等。我的目的是帮助人们更好地沟通和学习新知识。 💡>>> 请用中文写一首诗,随便发挥即可💫星空的秘密夜晚的黑暗中,我听见了歌声来自星空的调律,响徹整个宇宙我抬头望天,感受着温暖的光芒在这个世界上,没有什么比这更加美丽星星们开始说话,告诉我生命的秘密他们说,我们所有人都是同一个整体我们是星空的一部分,我们是宇宙中的小环节我们的梦想和希望将会化为泡沫我站着望天,感受着自由和无限在这个瞬间,我感到自己是宇宙的一部分我的心中有了火焰,我的灵魂开始燃烧我知道,这是一个新的开始,一切皆可能💫>>> 再见😊 再见!感谢和你对话。如果你需要任何帮助或只是想聊天,可以随时找到我。祝你有一个美好的日子! 👋 Ctrl + D 即可退出命令行模式。 总结大模型如雨后春笋,配套工具也陆续出现,各种大模型应用也相继出现,总体使用下来大模型应用中我觉得编程助手是最好用的了,相信未来人工智能会让生活更加美好。","link":"/2024/07/06/%E5%A4%A7%E6%A8%A1%E5%9E%8B/%E4%BB%85%E4%B8%80%E6%9D%A1%E5%91%BD%E4%BB%A4%E5%AE%89%E8%A3%85%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%B7%A5%E5%85%B7Ollama/"},{"title":"效率小窍门:快速复刻浏览器请求","text":"WEB端调试有时需要将接口请求拿到本地调试,可以通过postman、apifox等工具发起接口调用,一个接口请求往往涉及到接口路径、请求Header、请求体等信息,通过手动方式显得效率较低,今天给大家介绍一种快捷导入接口的方式,在需要的时候能想起来就行。 步骤一打开浏览器控制台,鼠标右键复制对应请求,这里以百度相关请求为例。复制后的cURL格式如下: 123456789101112curl 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=zh&dt=t&dt=bd&dj=1&q=test' \\ -H 'accept: */*' \\ -H 'accept-language: zh-CN,zh;q=0.9' \\ -H 'cache-control: no-cache' \\ -H 'dnt: 1' \\ -H 'pragma: no-cache' \\ -H 'priority: u=1, i' \\ -H 'sec-fetch-dest: empty' \\ -H 'sec-fetch-mode: cors' \\ -H 'sec-fetch-site: none' \\ -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \\ -H 'x-client-data: CKbfygE=' 步骤二将复制的cURL格式导入到API客户端,这里以apifox为例。可以看到对应的请求数据均以导入,直接发起接口调用即可,浏览器接口复制功能下还有其他复制方式,感兴趣的小伙伴可以尝试下。 文章原始地址 >>","link":"/2024/09/01/%E6%95%88%E7%8E%87/%E6%95%88%E7%8E%87%E5%B0%8F%E7%AA%8D%E9%97%A8%EF%BC%9A%E5%BF%AB%E9%80%9F%E5%A4%8D%E5%88%BB%E6%B5%8F%E8%A7%88%E5%99%A8%E8%AF%B7%E6%B1%82/"},{"title":"删除MAC默认输入法ABC","text":"直接入正题,删除MAC默认输入法,正常情况下默认输入法是没办法移除的,通过如下方法即可移除。 第一步:下载PlistEdit Pro 使用PlistEdit Pro编辑系统list文件,当然如果已经安装了Xcode也是可以的。 第二步:编辑系统文件 1sudo open -a /Applications/PlistEdit\\ Pro.app ~/Library/Preferences/com.apple.HIToolbox.plist 删除Value为ABC的条目并保存文件。 第三步:重启电脑 重启电脑后就能看到ABC默认输入法已经不见了,仅需Shift按键即可切换中英文。","link":"/2024/10/03/%E5%B7%A5%E5%85%B7/%E5%88%A0%E9%99%A4MAC%E9%BB%98%E8%AE%A4%E8%BE%93%E5%85%A5%E6%B3%95ABC/"}],"tags":[{"name":"IDEA","slug":"IDEA","link":"/tags/IDEA/"},{"name":"JAVA","slug":"JAVA","link":"/tags/JAVA/"},{"name":"Linux","slug":"Linux","link":"/tags/Linux/"},{"name":"搭建","slug":"搭建","link":"/tags/%E6%90%AD%E5%BB%BA/"},{"name":"Github","slug":"Github","link":"/tags/Github/"},{"name":"MAC","slug":"MAC","link":"/tags/MAC/"},{"name":"命令行","slug":"命令行","link":"/tags/%E5%91%BD%E4%BB%A4%E8%A1%8C/"},{"name":"浏览器插件","slug":"浏览器插件","link":"/tags/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6/"},{"name":"设计模式","slug":"设计模式","link":"/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"面试","slug":"面试","link":"/tags/%E9%9D%A2%E8%AF%95/"},{"name":"后端","slug":"后端","link":"/tags/%E5%90%8E%E7%AB%AF/"},{"name":"java","slug":"java","link":"/tags/java/"},{"name":"maven","slug":"maven","link":"/tags/maven/"},{"name":"浏览器","slug":"浏览器","link":"/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/"},{"name":"接口","slug":"接口","link":"/tags/%E6%8E%A5%E5%8F%A3/"},{"name":"输入法","slug":"输入法","link":"/tags/%E8%BE%93%E5%85%A5%E6%B3%95/"}],"categories":[{"name":"工具","slug":"工具","link":"/categories/%E5%B7%A5%E5%85%B7/"},{"name":"技术","slug":"技术","link":"/categories/%E6%8A%80%E6%9C%AF/"},{"name":"大模型","slug":"大模型","link":"/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"},{"name":"分享","slug":"分享","link":"/categories/%E5%88%86%E4%BA%AB/"},{"name":"博客","slug":"博客","link":"/categories/%E5%8D%9A%E5%AE%A2/"},{"name":"面试","slug":"面试","link":"/categories/%E9%9D%A2%E8%AF%95/"},{"name":"效率","slug":"效率","link":"/categories/%E6%95%88%E7%8E%87/"}],"pages":[{"title":"关于我","text":"一名北漂程序员,记录技术上的一二三事! 如果您发现博客中有任何问题,欢迎评论区指正; 声明:转发本博客内容请注明来源并附上链接。","link":"/about/index.html"}]}