Java对象之间相同属性的赋值
场景 两个不同的类,其中一部分的属性相同。 要把其中一个对象的一些属性赋值给另一个对象。 最原始的方式是依次调用两个对象的set和get方法,挨个赋值。 但是spring提供了BanUtils的方法copyPrpperties可以实现。 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书、教程推送与免费下载。 实现 引入包
1 |
import org.springframework.beans.BeanUtils; |
然后调用
1 |
BeanUtils.copyProperties(kqDkszJl,kqDksz); |
其中左边是要取值的对象,右边是要赋值的对象。 博客园: https://www.cnblogs.com/badaoliumangqizhi/ 关注公众号 霸道的程序猿 获取编程相关电子书、教程推送与免费下载。 from:https://www.cnblogs.com/badaoliumangqizhi/p/13786384.html
View Detailscom.alibaba.fastjson转换JSON数据后顺序与原JSON字符串顺序不一致原因分析
转换字符串示例:
1 2 |
String array2 = "{'i':'2','b':'3'}"; JSONObject parseObject = JSON.parseObject(array2); |
结果:
1 |
{"b":"3","i":"2"} |
我们会发现顺序与原来的字符串顺序不一致。 通过DEBUG去com.alibaba.fastjson.parser.DefaultJSONParser的下述方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
public Object parse(Object fieldName) { final JSONLexer lexer = this.lexer; switch (lexer.token()) { case SET: lexer.nextToken(); HashSet<Object> set = new HashSet<Object>(); parseArray(set, fieldName); return set; case TREE_SET: lexer.nextToken(); TreeSet<Object> treeSet = new TreeSet<Object>(); parseArray(treeSet, fieldName); return treeSet; case LBRACKET: JSONArray array = new JSONArray(); parseArray(array, fieldName); if (lexer.isEnabled(Feature.UseObjectArray)) { return array.toArray(); } return array; case LBRACE: //重点就是此行的lexer.isEnabled(Feature.OrderedField)=false JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField)); return parseObject(object, fieldName); // case LBRACE: { // Map<String, Object> map = lexer.isEnabled(Feature.OrderedField) // ? new LinkedHashMap<String, Object>() // : new HashMap<String, Object>(); // Object obj = parseObject(map, fieldName); // if (obj != map) { // return obj; // } // return new JSONObject(map); // } case LITERAL_INT: Number intValue = lexer.integerValue(); lexer.nextToken(); return intValue; case LITERAL_FLOAT: Object value = lexer.decimalValue(lexer.isEnabled(Feature.UseBigDecimal)); lexer.nextToken(); return value; |
重点就是此行的lexer.isEnabled(Feature.OrderedField)=false,打开JSONObject的源码构造方法可以发现当ordered参数值为false时使用的是HashMap存放数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public JSONObject(int initialCapacity, boolean ordered){ if (ordered) { map = new LinkedHashMap<String, Object>(initialCapacity); } else { map = new HashMap<String, Object>(initialCapacity); } } |
hashmap是数组加链表结构,根据key的hash算法确定在数组中的位置,当发生hash冲突的时候,根据二叉树或者红黑树构成链表。所以是有序的,key确定,位置也就确定了。 如果要实现转换前的数据顺序与转换后的数据顺序一致,可以使用如下方式:
1 2 3 |
String array2 = "{'i':'2','b':'3'}"; JSONObject parseObject = JSON.parseObject(array2, Feature.OrderedField); |
此时会使用LinkedHashMap,LinkedHashMap的内部维持了一个双向链表,保存了数据的插入顺序,遍历时,先得到的数据便是先插入的。 from:https://blog.csdn.net/h363659487/article/details/103880710
View Detailsspring-boot启动警告:No MyBatis mapper was found…
spring-boot继承mybatis启动时,警告如下: 2018-09-10 15:00:14.721 WARN tk.mybatis.spring.mapper.ClassPathMapperScanner --No MyBatis mapper was found in '[com.kevin]' package. Please check your configuration. 使用的tk的开源项目进行mybatis集成,百度了很多解决方案,最终看到一位前辈介绍:doScan()会扫描启动类同级目录下的mapper接口,但是合理的目录结果绝对不允许所有的mapper都在启动类目录下,所以在启动类目录下添加了一个伪mapper,如下: 再重新启动服务,就不会出现如上warn信息了…… from:https://my.oschina.net/kevin2kelly/blog/2046324 ========================================================================================= 光子:通过以上兄弟的方法,我的警告确实没有了。但经过dev-tools热启动后还是会提醒: 无法获取实体类com.w3cnet.doctoradvice.entity.HisvMzbrJzxx对应的表名 …… 还需要安装一下:Mapper Spring Boot Starter ,贴上地址:
1 2 |
// https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter compile group: 'tk.mybatis', name: 'mapper-spring-boot-starter', version: '2.1.5' |
折腾了几次,终于完美解决…… 参考:https://blog.csdn.net/zwrlj527/article/details/91824220
View DetailsCargo 教程
Cargo 是什么 Cargo 是 Rust 的构建系统和包管理器。 Rust 开发者常用 Cargo 来管理 Rust 工程和获取工程所依赖的库。在上个教程中我们曾使用 cargo new greeting 命令创建了一个名为 greeting 的工程,Cargo 新建了一个名为 greeting 的文件夹并在里面部署了一个 Rust 工程最典型的文件结构。这个 greeting 文件夹就是工程本身。 Cargo 功能 Cargo 除了创建工程以外还具备构建(build)工程、运行(run)工程等一系列功能,构建和运行分别对应以下命令:
1 2 |
cargo build cargo run |
Cargo 还具有获取包、打包、高级构建等功能,详细使用方法参见 Cargo 命令。 在 VSCode 中配置 Rust 工程 Cargo 是一个不错的构建工具,如果使 VSCode 与它相配合那么 VSCode 将会是一个十分便捷的开发环境。 在上一章中我们建立了 greeting 工程,现在我们用 VSCode 打开 greeting 文件夹(注意不是 runoob-greeting)。 打开 greeting 之后,在里面新建一个新的文件夹 .vscode (注意 vscode 前面的点,如果有这个文件夹就不需要新建了)。在新建的 .vscode 文件夹里新建两个文件 tasks.json 和 launch.json,文件内容如下: tasks.json 文件
1 2 3 4 5 6 7 8 9 10 11 |
{ "version": "2.0.0", "tasks": [ { "label": "build", "type": "shell", "command":"cargo", "args": ["build"] } ] } |
launch.json 文件(适用在 Windows 系统上)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
{ "version": "0.2.0", "configurations": [ { "name": "(Windows) 启动", "preLaunchTask": "build", "type": "cppvsdbg", "request": "launch", "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false }, { "name": "(gdb) 启动", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "miDebuggerPath": "这里填GDB所在的目录", "setupCommands": [ { "description": "为 gdb 启用整齐打印", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] } |
launch.json 文件(适用在 Linux 系统上)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "version": "0.2.0", "configurations": [ { "name": "Debug", "type": "gdb", "preLaunchTask": "build", "request": "launch", "target": "${workspaceFolder}/target/debug/${workspaceFolderBasename}", "cwd": "${workspaceFolder}" } ] } |
launch.json 文件(适用在 Mac OS 系统上)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "version": "0.2.0", "configurations": [ { "name": "(lldb) 启动", "type": "cppdbg", "preLaunchTask": "build", "request": "launch", "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "lldb" } ] } |
[…]
View DetailsRust 教程
Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率,它的执行效率也是令人称赞的,是一种少有的兼顾开发效率和执行效率的语言。 Rust 语言由 Mozilla 开发,最早发布于 2014 年 9 月。Rust 的编译器是在 MIT License 和 Apache License 2.0 双重协议声明下的免费开源软件。截至目前( 2020 年 1 月)最新的编译器版本是 1.41.0。 Rust 官方在线工具: https://play.rust-lang.org/。 Rust 系列文章内容由 Sobin 收集整理。 Rust语言的特点 高性能 – Rust 速度惊人且内存利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成。 可靠性 – Rust 丰富的类型系统和所有权模型保证了内存安全和线程安全,让您在编译期就能够消除各种各样的错误。 生产力 – Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息, 还集成了一流的工具 —— 包管理器和构建工具, 智能地自动补全和类型检验的多编辑器支持, 以及自动格式化代码等等。 Rust的应用 Rust 语言可以用于开发: 传统命令行程序 – Rust 编译器可以直接生成目标可执行程序,不需要任何解释程序。 Web 应用 – Rust 可以被编译成 WebAssembly,WebAssembly 是一种 JavaScript 的高效替代品。 网络服务器 – Rust 用极低的资源消耗做到安全高效,且具备很强的大规模并发处理能力,十分适合开发普通或极端的服务器程序。 嵌入式设备 – Rust 同时具有JavaScript 一般的高效开发语法和 C 语言的执行效率,支持底层平台的开发。 谁适合阅读本教程? 本教程对于初级的编程知识将默认读者已经掌握,所以如果你阅读本教程,你需要对初级的编程知识有一定的了解(最好已经初识 C/C++ 或 JavaScript 编程语言)。 第一个 Rust 程序 Rust 语言代码文件后缀名为 .rs, 如 runoob.rs。
1 2 3 |
fn main() { println!("Hello World!"); } |
参考链接 Rust 官方网站:https://www.rust-lang.org/zh-CN Rust 官方文档:https://doc.rust-lang.org/ Rust Play:https://play.rust-lang.org/ Visual Studio […]
View DetailsJava8 使用 stream().filter()过滤List对象(查找符合条件的对象集合)
内容简介 本文主要说明在Java8及以上版本中,使用stream().filter()来过滤一个List对象,查找符合条件的对象集合。 List对象类(StudentInfo)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
public class StudentInfo implements Comparable<StudentInfo> { //名称 private String name; //性别 true男 false女 private Boolean gender; //年龄 private Integer age; //身高 private Double height; //出生日期 private LocalDate birthday; public StudentInfo(String name, Boolean gender, Integer age, Double height, LocalDate birthday){ this.name = name; this.gender = gender; this.age = age; this.height = height; this.birthday = birthday; } public String toString(){ String info = String.format("%s\t\t%s\t\t%s\t\t\t%s\t\t%s",this.name,this.gender.toString(),this.age.toString(),this.height.toString(),birthday.toString()); return info; } public static void printStudents(List<StudentInfo> studentInfos){ System.out.println("[姓名]\t\t[性别]\t\t[年龄]\t\t[身高]\t\t[生日]"); System.out.println("----------------------------------------------------------"); studentInfos.forEach(s->System.out.println(s.toString())); System.out.println(" "); } @Override public int compareTo(StudentInfo ob) { return this.age.compareTo(ob.getAge()); //return 1; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Boolean getGender() { return gender; } public void setGender(Boolean gender) { this.gender = gender; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getHeight() { return height; } public void setHeight(Double height) { this.height = height; } public LocalDate getBirthday() { return birthday; } public void setBirthday(LocalDate birthday) { this.birthday = birthday; } } |
测试数据
1 2 3 4 5 6 |
//测试数据,请不要纠结数据的严谨性 List<StudentInfo> studentList = new ArrayList<>(); studentList.add(new StudentInfo("李小明",true,18,1.76,LocalDate.of(2001,3,23))); studentList.add(new StudentInfo("张小丽",false,18,1.61,LocalDate.of(2001,6,3))); studentList.add(new StudentInfo("王大朋",true,19,1.82,LocalDate.of(2000,3,11))); studentList.add(new StudentInfo("陈小跑",false,17,1.67,LocalDate.of(2002,10,18))); |
输出Students列表
1 2 |
//输出List StudentInfo.printStudents(studentList); |
输出结果如下图: 使用filter()过滤List
1 2 3 4 |
//查找身高在1.8米及以上的男生 List<StudentInfo> boys = studentList.stream().filter(s->s.getGender() && s.getHeight() >= 1.8).collect(Collectors.toList()); //输出查找结果 StudentInfo.printStudents(boys); |
结果如下图: from:https://www.cnblogs.com/codecat/p/10912454.html
View Detailsjava8 .stream().map().collect()用法
API: https://www.runoob.com/java/java8-streams.html
1 2 3 4 |
mylist.stream() .map(myfunction->{ return item; }).collect(Collectors.toList()); |
说明: steam():把一个源数据,可以是集合,数组,I/O channel, 产生器generator 等,转化成流。 forEach():迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数.
1 2 |
Random random = new Random(); random.ints().limit(10).forEach(System.out::println); |
map():用于映射每个元素到对应的结果。以下代码片段使用 map 输出了元素对应的平方数:
1 2 3 |
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); // 获取对应的平方数 List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); |
filter():filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
1 2 3 4 5 6 7 8 |
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 int count = strings.stream().filter(string -> string.isEmpty()).count(); limit limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据: Random random = new Random(); random.ints().limit(10).forEach(System.out::println); |
sorted(): 用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
1 2 3 4 5 6 7 8 9 |
Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println); 并行(parallel)程序 parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 int count = strings.parallelStream().filter(string -> string.isEmpty()).count(); 我们可以很容易的在顺序运行和并行直接切换。 |
Collectors(): 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
1 2 3 4 5 6 |
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("筛选列表: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("合并字符串: " + mergedString); |
from:https://blog.csdn.net/shine_guo_star/article/details/94383319
View Detailsjdk8的特性stream().map()
转: https://blog.csdn.net/sanchan/article/details/70753645 java8的optional的使用: http://www.jdon.com/idea/java/using-optional-effectively-in-java-8.html http://www.runoob.com/java/java8-optional-class.html Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。 Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。 Optional 类的引入很好的解决空指针异常。 类声明 以下是一个 java.util.Optional<T> 类的声明: public final class Optional<T> extends Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
在Java 8中stream().map(),您可以将对象转换为其他对象。查看以下示例: 1.大写字符串列表 1.1简单的Java示例将Strings列表转换为大写。 TestJava8.java package com.mkyong.java8; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class TestJava8 { public static void main(String[] args) { List<String> alpha = Arrays.asList("a", "b", "c", "d"); //Before Java8 List<String> alphaUpper = new ArrayList<>(); for (String s : alpha) { alphaUpper.add(s.toUpperCase()); } System.out.println(alpha); //[a, b, c, d] System.out.println(alphaUpper); //[A, B, C, D] // Java 8 List<String> collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList()); System.out.println(collect); //[A, B, C, D] // Extra, streams apply to any data type. List<Integer> num = Arrays.asList(1,2,3,4,5); List<Integer> collect1 = num.stream().map(n -> n * 2).collect(Collectors.toList()); System.out.println(collect1); //[2, 4, 6, 8, 10] } } 2.对象列表 - >字符串列表 2.1 name从staff对象列表中获取所有值。 Staff.java package com.mkyong.java8; import java.math.BigDecimal; public class Staff { private String name; private int age; private BigDecimal salary; //... } TestJava8.java package com.mkyong.java8; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class TestJava8 { public static void main(String[] args) { List<Staff> staff = Arrays.asList( new Staff("mkyong", 30, new BigDecimal(10000)), new Staff("jack", 27, new BigDecimal(20000)), new Staff("lawrence", 33, new BigDecimal(30000)) ); //Before Java 8 List<String> result = new ArrayList<>(); for (Staff x : staff) { result.add(x.getName()); } System.out.println(result); //[mkyong, jack, lawrence] //Java 8 List<String> collect = staff.stream().map(x -> x.getName()).collect(Collectors.toList()); System.out.println(collect); //[mkyong, jack, lawrence] } } 对象列表 - >其他对象列表 3.1此示例说明如何将staff对象列表转换为对象列表StaffPublic。 Staff.java package com.mkyong.java8; import java.math.BigDecimal; public class Staff { private String name; private int age; private BigDecimal salary; //... } StaffPublic.java package com.mkyong.java8; public class StaffPublic { private String name; private int age; private String extra; //... } 3.2 Java 8之前。 BeforeJava8.java package com.mkyong.java8; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class BeforeJava8 { public static void main(String[] args) { List<Staff> staff = Arrays.asList( new Staff("mkyong", 30, new BigDecimal(10000)), new Staff("jack", 27, new BigDecimal(20000)), new Staff("lawrence", 33, new BigDecimal(30000)) ); List<StaffPublic> result = convertToStaffPublic(staff); System.out.println(result); } private static List<StaffPublic> convertToStaffPublic(List<Staff> staff) { List<StaffPublic> result = new ArrayList<>(); for (Staff temp : staff) { StaffPublic obj = new StaffPublic(); obj.setName(temp.getName()); obj.setAge(temp.getAge()); if ("mkyong".equals(temp.getName())) { obj.setExtra("this field is for mkyong only!"); } result.add(obj); } return result; } } 输出 [ StaffPublic{name='mkyong', age=30, extra='this field is for mkyong only!'}, StaffPublic{name='jack', age=27, extra='null'}, StaffPublic{name='lawrence', age=33, extra='null'} ] 1 2 3 4 5 3.3 Java 8的例子。 NowJava8.java package com.mkyong.java8; package com.hostingcompass.web.java8; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class NowJava8 { public static void main(String[] args) { List<Staff> staff = Arrays.asList( new Staff("mkyong", 30, new BigDecimal(10000)), new Staff("jack", 27, new BigDecimal(20000)), new Staff("lawrence", 33, new BigDecimal(30000)) ); // convert inside the map() method directly. List<StaffPublic> result = staff.stream().map(temp -> { StaffPublic obj = new StaffPublic(); obj.setName(temp.getName()); obj.setAge(temp.getAge()); if ("mkyong".equals(temp.getName())) { obj.setExtra("this field is for mkyong only!"); } return obj; }).collect(Collectors.toList()); System.out.println(result); } } [ StaffPublic{name='mkyong', age=30, extra='this field is for mkyong only!'}, StaffPublic{name='jack', age=27, extra='null'}, StaffPublic{name='lawrence', age=33, extra='null'} ] |
from:https://www.cnblogs.com/fengli9998/p/9002377.html
View DetailsDapperExtensions扩展,一个不再更新的小众类库的踩坑之路
公司一个项目要从.net framework平台转成.net core平台,都是为了跨平台啊。 老的项目中用了个小众的类库:DapperExtensions。 有个同事直接nuget安装了该类库的.net core版本:DapperExtensions.NetCore,然后一直报错;于是向我求助。 报错代码如下图: 报错信息: P.S 同事用的是异步调用,同步调用是没问题的。 由于此类库不再更新,官网也没有了……也找不到文档; 在网上很少的资料中,都是些简单的示例,使用的都是同步调用,但同事用的是异步调用。我们一块折腾了半个上午,也没解决。但还不想放弃啊……于是又双叒叕重新撸了n遍,豁然发现:生成的MySQL语句里怎么会有中括号!灯下黑~…… 于是,网上一通搜,终于找到一篇说SQL方言的文档,看了一下DapperExtensions的源码,发现也有设置SQL方言的方法:
1 |
DapperExtensions.DapperExtensions.SqlDialect = new MySqlDialect(); |
运行……还是报错……%~@#¥,没起作用!无奈……拉倒吧,把代码改为同步调用吧。 还是不想放弃,再看一眼吧——竟然发现DapperExtensions的源码中异步方法和同步方法的SQL方言竟然是单独设置的,这类库设计的也没谁了……,于是设置了一下异步的SQL方言为MySQL,终于解决了。代码如下:
1 |
DapperExtensions.DapperAsyncExtensions.SqlDialect = new MySqlDialect(); |
总结: 不要使用小众类库,尤其是个人开发的。因为出了问题太难解决了。 解决问题要细心,更要有耐心;放空思想,从头多撸几遍。 小众类库的代码设计考虑不周: a. 比如说,代码已经写为new MySqlConnection(ConnString),SQL方言就应该自动设置为MySQL了。 b. 另一个,对于SQL方言,设置一次就行了,不应该设计成异步要单独设置。 解决过程实属不易,希望能帮助大家,谢谢~
View DetailsSQL注入测试
简介 SQL 注入是一种专门针对SQL语句的攻击方式。通过把SQL命令插入到web表单提交、输入域名或者页面请求的查询字符串中,利用现有的程序,来非法获取后台的数据库中的信息。在web的测试中涉及到的会比较多些。 注入原理 存在注入的原因是后台在编写程序时,没有对用户输入的数据做过滤。 例: 1、用户在某个输入框提交的参数是123。 浏览器提交的URL为: http://www.xxx.com/index.php?id=123 服务器后台执行SQL语句:select * from table1 where id = 123 此时是没有任何影响的。 2、 如果用户提交的参数是 123;drop table 服务器后台执行SQL语句: select * from table1 where id =123 ; drop table 相当于后台执行了两条SQL语句,查表,并且把table删除, 从而导致了SQL注入 检测注入的方法 目前主要有两种检测方式: 一、手工注入检测流程: 1. 判断是否存在注入点 www.abc.com/index.php?id=2 www.abc.com/index.php?id=2 and 1=1 www.abc.com/index.php?id=2 and 1=2 第2条返回正常, 第1,3条返回不正常说明id参数存在注入漏洞 2. 判定是否存在admin表 www.abc.com/index.php?id=2 and exists(select * from admin) 返回正常,存在admin表 3. 猜admin表中的字段名 www.abc.com/index.php?id=2 and exists(select username from admin) 返回正常 表示admin表存在username字段 4. 检测其他sql操作 二、工具检测: sqlmap: sqlmap是一个开源的渗透测试工具,可以用来进行自动化检测,利用SQL注入漏洞,获取数据库服务器的权限。 1. 下载地址 https://github.com/sqlmapproject/sqlmap.git 2. 常用命令 测试 以一个sqlmap检测URL为例: […]
View Details