项目自学记录1


项目自学记录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=`+<asc
fl 指定返回的域名,多个域名用逗号或者空格分隔,默认返回所有域
wt 指定响应的格式,例如xml、json等;

在Solr中提供了运算符,通过运算符我们就可以进行组合查询。

运算符 说明
? 通配符,替代任意单个字符(不能在检索的项开始使用*或者?符号)
* 通配符,替代任意多个字符(不能在检索的项开始使用*或者?符号)
~ 表示相似度查询,如查询类似于”roam”的词,我们可以这样写:roam将找到形如foam和roams的单词;roam0.8,检索返回相似度在0.8以上的文档。 邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
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">

文章作者: 爱敲代码の鱼儿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 爱敲代码の鱼儿 !
  目录