项目自学记录1
@RequestParam注解
https://www.cnblogs.com/tomingto/p/11377138.html
有三个属性:
(1)value:请求参数名(必须配置)
不对,是不一定要配。如果前端传的数据和后端的变量名一样,就不用。如果不一样,value里的值就是前端传的值。
(2)required:是否必需,默认为 true,即 请求中必须包含该参数,如果没有包含,将会抛出异常(可选配置)
(3)defaultValue:默认值,如果设置了该值,required 将自动设为 false,无论你是否配置了required,配置了什么值,都是 false(可选配置)
@ResponseBody注解 和 @RequestBody 注解
先看代码:
@Controller
public class LoginController {
@CrossOrigin
@PostMapping(value = "api/login")
@ResponseBody
public Result login(@RequestBody User requestUser) {
// 对 html 标签进行转义,防止 XSS 攻击
String username = requestUser.getUsername();
username = HtmlUtils.htmlEscape(username);
if (!Objects.equals("admin", username) || !Objects.equals("123456", requestUser.getPassword())) {
String message = "账号密码错误";
System.out.println(message);
return new Result(400);
} else {
return new Result(200);
}
}
}
从位置可以看出来,@ResponseBody是支持返回值为JSON.或者说,@ResponseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。 而@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)。
在MySQL中datetime和和 timestamp 的区别与选择
1.1 占用空间
类型 占据字节 表示形式
datetime 8 字节 yyyy-mm-dd hh:mm:ss
timestamp 4 字节 yyyy-mm-dd hh:mm:ss
1.2 表示范围
类型 表示范围
datetime ‘1000-01-01 00:00:00.000000’ to ‘9999-12-31 23:59:59.999999’
timestamp ‘1970-01-01 00:00:01.000000’ to ‘2038-01-19 03:14:07.999999’
timestamp翻译为汉语即”时间戳”,它是当前时间到 Unix元年(1970 年 1 月 1 日 0 时 0 分 0 秒)的秒数。对于某些时间的计算,如果是以 datetime 的形式会比较困难,假如我是 1994-1-20 06:06:06 出生,现在的时间是 2016-10-1 20:04:50 ,那么要计算我活了多少秒钟用 datetime 还需要函数进行转换,但是 timestamp 直接相减就行。
1.3 时区
timestamp 只占 4 个字节,而且是以utc的格式储存, 它会自动检索当前时区并进行转换。
datetime以 8 个字节储存,不会进行时区的检索.
也就是说,对于timestamp来说,如果储存时的时区和检索时的时区不一样,那么拿出来的数据也不一样。对于datetime来说,存什么拿到的就是什么。
还有一个区别就是如果存进去的是NULL,timestamp会自动储存当前时间,而 datetime会储存 NULL。
在mysql中存储数据,长文本
TINYTEXT -> 256 bytes.
TEXT -> 64kb
MEDIUMTEXT -> 16MB
LONGTEXT-> 4GB
CHAR 常用来存储固定长度的字符串,VARCHAR 常用来存储可变长度的字符串
VARCHAR(M) 能设置的最大长度
M 限制了 VARCHAR 能存储的字符串的最大长度,注意,是字符,不是字节,其有效值范围为 0 ~ 65535。虽然可设置的范围是 0 ~ 65535,但 M 真的就能设置为65535 吗?
对于utf8mb4字符集,M最大只能设置为16383。对于utf8字符集,M最大只能设置为21845。这两个数值是怎么计算出来的呢?
在utf8mb4字符集中,最多需要4个字节来表示一个字符,所以 65535 / 4 = 16383 。而在utf8字符集中,最多需要3个字节来表示一个字符,所以 65535 / 3 = 21845。
由此来看,在设置 M 的大小时,起决定作用的并不是 M 的有效值范围(0 ~ 65535),而是 M * 字符集的最大字节数不能超过65535个字节。
为什么不能超过 65535 字节呢?因为MySQL限制了一条记录的最大长度就是 65535 字节
自动生成mapper文件和实体类(通过数据库的表)
使用mybatisX插件https://www.cnblogs.com/6543x1/p/15484098.html
不过一些参数要修改
不选options里的Actual Column才能进行驼峰体的大小写转换。
然后上面第一张图生成的是实体类,第二张图生成的是下面俩文件,一个mapper一个xml
mybatis插入操作的一些配置
https://blog.csdn.net/zongf0504/article/details/100103946
insert 有几个常用的属性:
id: sql 片段在命名空间内的唯一标识. 和mapper 中方法名保持一致
useGeneratedKeys: 是否回填自动生成的主键
keyProperty: 主键回填到哪个属性
keyColumn: 主键回填的字段名, 可省略
parameterType: 参数类型, 通常都可以省略.
flushCache: 是否刷新(清空)一级缓存和二级缓存, 默认为true. 笔者尝试设置为false,并不生效. 所以使用默认即可.
timeout: sql 执行超时时间, 默认未设置, 由数据库驱动决定.
statementType: 执行sql时使用的statement类型, 默认为PREPARED. 可选值为:STATEMENT,PREPARED 或 CALLABLE 的一个
mybatis查询操作的一些操作
select的一个传参操作。要用到@Param
@Select(“select id,user_name,password,age from tb_users2 where id = #{id} and user_name = #{name} “)
User getUser5(@Param(“id”) Long id,@Param(“name”) String username);
前后端参数名称不一致时
对于函数里的单个参数。
public LogUtils getMessage(
@RequestParam(value="username",defaultValue="0",required=false)String username,
Integer pageCurrent) {}
//这里的value为前端传递的参数名称,required=false为前端也可以不传此参数
//defaultValue="0" 若是没有传这个参数,这个参数默认为0
对于函数里面是一个大对象的
public class ParamTest {
@JsonProperty("webParam")
private String controllerParam;
}
将日期转为2023-07-09的写法
SimpleDateFormat sim1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
SimpleDateFormat sim2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s1 = "Tue Sep 08 23:58:09 CST 2020";
try {
Date date = sim1.parse(s1);
System.out.println(date);
System.out.println(sim2.format(date));
}catch (ParseException e ){
e.printStackTrace();
}
输出为:
Tue Sep 08 23:58:09 CST 2020
2020-09-08 23:58:09
但是你要记得转字符串 toString() 和 取子串subString(startindex,endindex);
将2023-07-09字符串转为为Date类型
public class DateTest {
public static void main(String[] args) throws ParseException {
String dateStr1 = "2023-04-08 15:39:25";
String dateStr2 ="2023-04-05";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
Date dateResult = null;
dateResult = sdf2.parse(dateStr1);
System.out.println(dateResult.toString());
}
}
可以转换,转换结果为凌晨0点
Sat Apr 08 00:00:00 CST 2023
一些解除疑惑:函数名一样,父类子类调用
public class ExtTest3 {
public static void func(ExtTest test1){
System.out.println("test1");
}
public static void func(ExtTest2 test1){
System.out.println("test2");
}
public static void main(String[] args) {
ExtTest t1=new ExtTest(1);
ExtTest2 t2=new ExtTest2(2,3);
func(t1); //test1
func(t2); //test2
}
}
ExtTest2是ExtTest1 的子类,发现是符合预期的输出的。
Solr查询语法/参数 和 基础知识
基本查询参数
参数名 | 描述 |
---|---|
q | 查询条件,必填项 |
fq | 过滤查询 |
start | 结果集第一条记录的偏移量,用于分页,默认值0 |
rows | 返回文档的记录数,用于分页,默认值10 |
sort | 排序,格式:sort=` |
fl | 指定返回的域名,多个域名用逗号或者空格分隔,默认返回所有域 |
wt | 指定响应的格式,例如xml、json等; |
在Solr中提供了运算符,通过运算符我们就可以进行组合查询。
运算符 | 说明 |
---|---|
? | 通配符,替代任意单个字符(不能在检索的项开始使用*或者?符号) |
* | 通配符,替代任意多个字符(不能在检索的项开始使用*或者?符号) |
~ | 表示相似度查询,如查询类似于”roam”的词,我们可以这样写:roam |
AND | 表示且,等同于 “&&” |
OR | 表示或,等同于 “||” |
NOT | 表示否 |
() | 用于构成子查询 |
[] | 范围查询,包含头尾 |
{} | 范围查询,不包含头尾 |
+ | 存在运算符,表示文档中必须存在 “+” 号后的项 |
- | 不存在运算符,表示文档中不包含 “-” 号后的项 |
q和fq两个参数的区别
从使用上:q必须传递参数,fq可选的参数。在执行查询的时候,必须有q,而fq可以有,也可以没有;
从功能上:q有2项功能
第一项:根据用户输入的查询条件,查询符合条件的文档。
第二项:使用相关性算法,匹配到的文档进行相关度排序。
fq只有一项功能
对匹配到的文档进行过滤,不会影响相关度排序,效率高;
特殊情况:某些文档book_price域值为null,null值排在最前面还是最后面。
定义域类型的时候需要指定2个属性sortMissingLast,sortMissingFirst
sortMissingLast=true,无论升序还是降序,null值都排在最后
sortMissingFirst=true,无论升序还是降序,null值都排在最前
<fieldtype name="fieldName" class="xx" sortMissingLast="true" sortMissingFirst="false"/>
上面是在managed-schema里写的
facet 是 solr 的高级搜索功能之一 ,可以根据用户搜索条件 ,按照指定域进行分组并统计,类似于关系型数据库中的group by分组查询;
http://localhost:8080/solr/collection1/select?q=item_title:手机&facet=on&facet.field=item_brand
facet下面也有很多参数。facet.range下面也有很多参数。
solr group作用:将具有相同字段值的文档分组,并返回每个组的顶部文档。 Group和Facet的概念很像,都是用来分组,但是分组的结果是不同;
q=item_title:手机
&group=true
&group.field=item_brand
group分组结果和Fact分组查询的结果完全不同,他把同组的文档放在一起,显示该组文档数量,仅仅展示了第一个文档。
高亮显示是指根据关键字搜索文档的时候,显示的页面对关键字给定了特殊样式, 让它显示更加突出,如下面商品搜索中,关键字变成了红色,其实就是给定了红色样 ;
在Solr中提供了常用的3种高亮的组件(Highlighter)也称为高亮器,来支持高亮查询。
Unified Highlighter
Unified Highlighter是最新的Highlighter(从Solr6.4开始),它是最性能最突出和最精确的选择。它可以通过插件/扩展来处理特定的需求和其他需求。官方建议使用该Highlighter,即使它不是默认值。
Original Highlighter
Original Highlighter,有时被称为”Standard Highlighter” or “Default Highlighter”,是Solr最初的Highlighter,提供了一些定制选项,曾经一度被选择。它的查询精度足以满足大多数需求,尽管它不如统一的Highlighter完美;
FastVector Highlighter
FastVector Highlighter特别支持多色高亮显示,一个域中不同的词采用不同的html标签作为前后缀。
Solr从1.4开始便提供了Query Suggest,Query Suggest目前是各大搜索应用的标配,主要作用是避免用户输入错误的搜索词,同时将用户引导到相应的关键词上进行搜索。Solr内置了Query Suggest的功能,它在Solr里叫做Suggest模块. 使用该模块.我们通常可以实现2种功能。拼写检查(Spell-Checking),再一个就是自动建议(AutoSuggest)。
SolrJ
Solr官方就推出了一套专门操作Solr的java API,叫SolrJ。
使用SolrJ操作Solr会比利用RestTemplate来操作Solr要简单。SolrJ底层还是通过使用httpClient中的方法来完成Solr的操作.
SolrJ核心的API
SolrClient
HttpSolrClient:适合于单节点的情况下和Solr进行交互。
CloudSolrClient:适合于集群的情况下和Solr进行交互。
索引
添加
需求:添加一个图书文档。
添加有很多重载方法,SolrJ中支持添加一个文档,也支持一次添加文档集合。
@Test
public void testAddDocument() throws IOException, SolrServerException {
//创建文档
SolrInputDocument document = new SolrInputDocument();
//指定文档中的域
document.setField("id", "889922");
document.setField("item_title","华为 Meta30 高清手机");
document.setField("item_price", 20);
document.setField("item_images", "21312312.jpg");
document.setField("item_createtime", new Date());
document.setField("item_updatetime", new Date());
document.setField("item_category", "手机");
document.setField("item_brand","华为");
//添加文档
httpSolrClient.add(document);
httpSolrClient.commit();
}
修改
如果文档id相同就是修改;
@Test
public void testAddDocument() throws IOException, SolrServerException {
//创建文档
SolrInputDocument document = new SolrInputDocument();
//指定文档中的域
document.setField("id", "889922");
document.setField("book_name","SolrJ是Solr提供的操作Solr的javaAPI,挺好用");
document.setField("book_num", 20);
document.setField("book_pic", "21312312.jpg");
document.setField("book_price", 20.0);
//添加文档
httpSolrClient.add(document);
httpSolrClient.commit();
}
删除
支持基于id删除,支持基于条件删除。
基于id删除
@Test
public void testDeleteDocument() throws IOException, SolrServerException {
httpSolrClient.deleteById("889922");
httpSolrClient.commit();
}
支持基于条件删除,删除所有数据要慎重
@Test
public void testDeleteQuery() throws IOException, SolrServerException {
httpSolrClient.deleteByQuery("book_name:java"); //*:*删除所有
httpSolrClient.commit();
}
到这关于使用SolrJ完成索引相关的操讲解完毕。下面讲解查询。
基本查询
主查询+过滤查询
查询的操作分为很多种下面我们讲解基本查询。
核心的API方法:
solrClient.query(SolrParams);
SolrParams是一个抽象类,通常使用其子类SolrQuery封装查询条件;
查询item_title中包含手机的商品
@Test
public void testBaseQuery() throws IOException, SolrServerException {
//封装查询条件
SolrQuery params = new SolrQuery();
//设置查询条件,参数1:查询参数,q,fq...
params.setQuery("item_title:手机");
//执行查询,获取结果
QueryResponse resp = httpSolrClient.query(params);
//满足条件的文档
SolrDocumentList results = resp.getResults();
//迭代results
for (SolrDocument result : results) {
System.out.println(result.get("id") + "--" + result.get("item_title"));
}
//获取总记录
long numFound = results.getNumFound();
System.out.println(numFound);
}
这是关于我们这一块核心API,接下来我们在这个基础上。我们做一些其他操作。添加过滤条件:品牌是华为。
价格在[1000-2000].
注意:过滤条件可以添加多个,所以使用的是SolrQuery的add方法。如果使用set后面过滤条件会将前面的覆盖.
@Test
public void testBaseFilterQuery() throws IOException, SolrServerException {
//封装查询条件
SolrQuery params = new SolrQuery();
//设置查询条件,参数1:查询参数,q,fq...
params.setQuery("item_title:手机");
params.addFilterQuery("item_brand:华为");
params.addFilterQuery("item_price:[1000 TO 2000]");
//执行查询,获取结果
QueryResponse resp = httpSolrClient.query(params);
//满足条件的文档
SolrDocumentList results = resp.getResults();
//迭代results
for (SolrDocument result : results) {
System.out.println(result.get("id") + "--" + result.get("item_title") + "---" + result.get("item_brand") + "---" + result.get("item_price"));
}
//获取总记录
long numFound = results.getNumFound();
System.out.println(numFound);
}
分页
接下来我们要完成的是分页,需求:在以上查询的条件查询,查询第1页的20条数据。
params.setStart(10);
params.setRows(10);
排序
除了分页外,还有排序。需求:按照价格升序。如果价格相同,按照id降序。
params.addSort("item_price,",Order.desc);
params.addSort("id",Order.asc);
域名起别名
到这基本查询就基本讲解完毕。有时候我们需要对查询结果文档的字段起别名。
需求:将域名中的item_去掉。
//指定查询结果的字段列表,并且指定别名
params.setFields("id,price:item_price,title:item_title,brand:item_brand,category:item_category,image:item_image");
System.out.println(result.get("id") + "--" + result.get("title") + "---" + result.get("brand") + "---" + result.get("category"));
别名指定完毕后,便于我们后期进行封装;到这关于基本查询讲解完毕,下面讲解组合查询。
组合查询
需求:查询Item_title中包含手机或者平板电视的文档。
params.setQuery("q","item_title:手机 OR item_title:平板电视");
需求:查询Item_title中包含手机 并且包含三星的文档
params.setQuery("item_title:手机 AND item_title:三星");
params.setQuery(,"+item_title:手机 +item_title:三星");
需求: 查询item_title中包含手机但是不包含三星的文档
params.setQuery("item_title:手机 NOT item_title:三星");
params.setQuery("+item_title:手机 -item_title:三星");
需求:查询item_title中包含iphone开头的词的文档,使用通配符。;
params.setQuery("item_title:iphone*");
到这关于SolrJ中组合查询我们就讲解完毕了。
Date你新new一个对象,Date的值不是空,是当前的时间。
python中关于处理excel的一些代码
import pandas as pd
import re
df = pd.read_excel('D:\company\中国电信税收政策法律库\税务知识库标签及文件分工.xlsx',engine='openpyxl')
\# array = pd.values[: , 2]
\# 提取文件号和文件名称中的信息
\# 根据文件号和文件名称推断发文部门
\#df['发文部门'] = df['文件号'].str.extract(r'([\u4e00-\u9fa5]+)')
\# 使用正则表达式替换发文部门列中的内容(包含国务院则替换为国务院)
\#df['发文部门'] = df['发文部门'].replace(to_replace=r'.*国务院.*', value='国务院', regex=True)
\#df['发文部门'] = df['发文部门'].replace(to_replace=r'.*主席令.*', value='主席令', regex=True)
df['发文部门'] = df['发文部门'].replace(to_replace=r'.*修.*', value='', regex=True)
\# 在原始Excel文件中添加发文部门列
df.to_excel('D:\company\中国电信税收政策法律库\税务知识库标签及文件分工.xlsx', index=False)
Java中的高亮注释 //TODO
使用//todo 代替一般的注释//
可以呈现高亮,而且使用快捷键ALT+6还能快速查找所有todo注释
Java中用easyExcel来读取excel
https://blog.csdn.net/u010925982/article/details/117412753
用到了@ExcelProperty(value = “文件名称”) 与excel文件的表头对应
Mybatis 将Java实体对象与数据库一行的对象深度绑定
在项目中发现如下现象:
在第一个断点,versionID是没有值的
在第二个断点就有值了
对一个数据库的插入操作,数据库里默认生成的新的递增主键,会影响到Java类的实体对象。这是mybatis做的,将自增主键回填到id了。
要进行如下配置,比如在KbKlLawExtMapper.xml里
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.zbiti.kbss.model.KbKlLawExt" useGeneratedKeys="true">