解析xml数据存入bean映射到数据库的 需求解决过程
解析xml数据存入bean映射到数据库的 需求解决过程
2017年12月19日 15:18:57 守望dfdfdf 阅读数:419 标签: xmlbean 更多
个人分类: 工作 问题
编辑
版权声明:本文为博主原创文章,转载请注明文章链接。 https://blog.csdn.net/xiaoanzi123/article/details/78843037
首先贴上已知的一段代码demo,解析xml。按照此方式进行功能开发。
package com.iflytek.zhejiang.hangzhou.qlsx.serviceimpl;
import java.util.List;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
public class XMLParserSample {
public static XMLParserSample getConf() {
try {
return parse();
} catch (ConfigurationException e) {
e.printStackTrace();
}
return null;
}
private static XMLParserSample parse() throws ConfigurationException {
Configuration config = new XMLConfiguration(XMLParserSample.class.getClassLoader().getResource("conf.xml"));
String ip = config.getString("dataBaseURI");
String account = config.getString("account");
String password = config.getString("password");
String runTime = config.getString("runTime");
List<?> tasks = config.getList("tasks.table[@name]");
// List<Table> tblLst = new ArrayList<Table>();
// for (int i = 0; i < tasks.size(); i++) {
//
// Table tbl = new Table();
// tbl.setName(config.getString(String.format(
// "tasks.table(%d)[@name]", i)));
// tbl.setInfo(config.getString(String.format(
// "tasks.table(%d)[@info]", i)));
// tbl.setPrimary(config.getString(String.format(
// "tasks.table(%d)[@primary]", i)));
// tbl.setColumns(config.getList(String.format(
// "tasks.table(%d).columns", i)));
// tbl.setTemplate(config.getString(String.format(
// "tasks.table(%d)[@template]", i)));
// tbl.setWaitTime(config.getString(String.format(
// "tasks.table(%d)[@waitTime]", i)));
// tbl.setRunTime(config.getString(String.format(
// "tasks.table(%d)[@runTime]", i)));
// tbl.setSingle(config.getString(String.format(
// "tasks.table(%d)[@single]", i)));
// tbl.setUrl(config.getString(String.format("tasks.table(%d).url", i)));
//
// if ( StringUtils.equals(TaskType.MULTI_GETTER, tbl.getTemplate())) {
// TableItem item = new TableItem();
//
// item.setName(config.getString(String.format(
// "tasks.table(%d).item[@name]", i)));
// item.setInfo(config.getString(String.format(
// "tasks.table(%d).item[@info]", i)));
// item.setRef(config.getString(String.format(
// "tasks.table(%d).item[@ref]", i)));
// item.setColumns(config.getList(String.format(
// "tasks.table(%d).item.columns", i)));
// item.setUrl(config.getString(String.format("tasks.table(%d).item.url", i)));
//
// tbl.setItem(item);
// }
//
// tblLst.add(tbl);
// }
//
// gc.setTblLst(tblLst);
//
// return gc;
//
return null;
}
}
有以下几点不理解:
①List<?> tasks = config.getList("tasks.table[@name]");是什么?tasks、table我猜测是conf.xml里面的开头的标签【根标签附近的层级的标签】名字,具体我也没有conf.xml的内容格式,不知是啥。
XMLParserSample.class.getClassLoader().getResource("conf.xml")
这一串的意思像是利用了反射的知识内容,获取解析器?
②Configuration 这种解析xml文件的方式我没接触过,之前只知道sax和dom4j。经过资料查询,算是有所了解学习。参考 http://blog.csdn.net/t1dmzks/article/details/64500731 ,
Apache Commons Configuration 读取xml文件的功能。参考:http://blog.csdn.net/qq_30739519/article/details/50865526
③config.getString(String.format("tasks.table(%d)[@name]", i)));
这种写法一方面是String的format方法的使用,相关知识可以参考 http://blog.csdn.net/lonely_fireworks/article/details/7962171/
另一方面,结合②,[@name]这种语法是 XPATH的知识点。关于XPATH,我突然想起俩年前初学php入门时好像学过了解下,不过一直没用到过,现在竟然忘得一干二净认不出来,-_-||
demo中的实体bean Table类,demo中没有对应的代码,也没有conf.xml文件,还有最后的那个gc,都不知道是干啥的,导致我很不理解疑问①的遍历getList()到底是什么原理。一脸懵。循环体中无非就是从xml取出对应数据封装到实体bean的属性里面,dao层用的hibernate,但是demo里面没有sql,所以我才猜测是利用的hibernate和数据库表的映射关系来存储数据的,个人也没有学习过hibernate,只是有点接触。最后返回的对象是什么gc是什么也是一头雾水。以上为开发前对demo的整体感受简述。
开发需求说明:
AAAA表中,ROWGUID、UPDATE_DATE两个字段作联合主键(存在ROWGUID相同UPDATE_DATE不同的多条记录),另有一个字段MATERIAL_INFO,存的就是下述xml内容的字符串形式的数据。我的任务就是取出这三个字段的值,封装到三个新建表【建表语句在下面】对应的三个java bean里面,然后映射数据入库。(多条记录ROWGUID相同就取UPDATE_DATE最大的那条数据),另有过滤条件process=0,sql如下:
select ROWGUID ,max(UPDATE_DATE) UPDATE_DATE,MATERIAL_INFO from AAAA where PROCESS = '0' group by ROWGUID ";
取出数据后,因为存放到三张表里面。表与表之间的字段关联关系全在下面的建表语句的注释中说明了(稍微有点复杂,熟悉了就好理解了)
贴上要开发分析的xml文件的内容格式:
<?xml version="1.0" encoding="utf-8"?>
<DATAAREA>
<CHANGE_FLAG>1</CHANGE_FLAG>
<MATERIALS>
<MATERIAL>
<MATERIALGUID>2fadsfdsfsdc22ed9d</MATERIALGUID>
<NAME>水电费水电费水电费</NAME>
<FORMAT>1</FORMAT>
<DETAIL_REQUIREMENT>一份</DETAIL_REQUIREMENT>
<NECESSITY>1</NECESSITY>
<NECESSITY_DESC/>
<MATERIAL_RES/>
<IS_RQ/>
<EMPTYTABLE>
<FILENAME/>
<FILECONTENT/>
<FILEURL/>
</EMPTYTABLE>
<EXAMPLETABLE>
<FILENAME/>
<FILECONTENT/>
<FILEURL/>
</EXAMPLETABLE>
<BAK/>
</MATERIAL>
<MATERIAL>
<MATERIALGUID>1fsdfdsfsd07a525a</MATERIALGUID>
<NAME>发送到发的所发生的</NAME>
<FORMAT>1</FORMAT>
<DETAIL_REQUIREMENT>1份</DETAIL_REQUIREMENT>
<NECESSITY>1</NECESSITY>
<NECESSITY_DESC/>
<MATERIAL_RES/>
<IS_RQ/>
<EMPTYTABLE>
<FILENAME/>
<FILECONTENT/>
<FILEURL/>
</EMPTYTABLE>
<EXAMPLETABLE>
<FILENAME/>
<FILECONTENT/>
<FILEURL/>
</EXAMPLETABLE>
<BAK/>
</MATERIAL>
......等多个<MATERIAL></MATERIAL>
</MATERIALS>
</DATAAREA>
新建三张表的建表语句:【表之间存在 逻辑外键的关系连接】
DROP TABLE IF EXISTS `material_info`; CREATE TABLE `material_info` ( `MATERIALGUID` ) NOT NULL COMMENT '主键 材料标识', `QLSX_ROWGUID` ) NOT NULL COMMENT ' AAAA 表中的rowguid对应的字段值', `QLSX_UPDATE_DATE` datetime NOT NULL COMMENT ' AAAA 表中的update_date对应的字段值', `NAME` ) NOT NULL COMMENT '材料名称', `FORMAT` ) COMMENT '材料形式,代码项:材料形式', `DETAIL_REQUIREMENT` ) COMMENT '材料详细要求', `NECESSITY` ) COMMENT '材料必要性,代码项:材料必要性', `NECESSITY_DESC` ) COMMENT '材料必要性描述', `IS_RQ` ) COMMENT '', `BAK` ) COMMENT '备注', `UPDATE_DATE` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`materialguid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权力事项库-申报材料主表'; DROP TABLE IF EXISTS `material_res`; CREATE TABLE `material_res` ( `ID` bigint unsigned auto_increment COMMENT '物理主键,无意义', `MATERIALGUID` ) NOT NULL COMMENT '逻辑主键,参照material_info表中对应的materialguid字段值', `MATERIAL_RES` ) COMMENT '材料出具单位', `EXAMPLETABLE` ) ' NOT NULL COMMENT 'FILENAME、FILECONTENT、FILEURL的xml中的父标签是否为EXAMPLETABLE 1是 0不是', `FILENAME` ) COMMENT '空白表格文件名称(完整文件名,带后缀)', `FILECONTENT` longtext COMMENT '文件内容,BASE64编码格式', `FILEURL` ) COMMENT '附件链接地址(公有云地址)', `UPDATE_DATE` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权力事项库-申报材料出具单位和材料信息表'; DROP TABLE IF EXISTS `material_trans_log`; CREATE TABLE `material_trans_log` ( `ID` bigint unsigned auto_increment COMMENT '物理主键,无意义', `QLSX_ROWGUID` ) NOT NULL COMMENT ' AAAA 表中的rowguid对应的字段值', `QLSX_UPDATE_DATE` datetime NOT NULL COMMENT ' AAAA 表中的update_date对应的字段值', `QLSX_CHANGE_FLAG` ) NOT NULL COMMENT '0:未变化,1:变化', `CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权力事项库-申报材料解析入库的日志表';
取出三个字段的值,做参数传给自己写的xml解析方法parse();在解析方法中进行xml解析并进行对应bean的封装。
经过请示可以不必非要按照demo,果断改用dom4j开始解析赋值。自己的代码如下【踩坑提示:在处理xml时,一定要注意标签之间的层级关系以及数量关系,不然容易出现逻辑错误】】:
public XmlParserVO parse(String rowguid,Timestamp updatedate,String materialinfo) throws DocumentException {//参数就是刚刚取出的三个字段的值
Document document = DocumentHelper.parseText(materialinfo); // materialinfo 为xml格式字符串
//一个xml就一个 CHANGE_FLAG 标签,不在material标签内部,故在遍历前取出
String changeFlag = document.selectSingleNode("/DATAAREA/CHANGE_FLAG").getText();
//materialinfo MaterialInfo MaterialTransLog 为新建三张表对应的类bean
List<MaterialRes> listRes = new ArrayList<MaterialRes>();
List<MaterialInfo> listInfo = new ArrayList<MaterialInfo>();
MaterialTransLog materialtrauslog = new MaterialTransLog();
materialtrauslog.setQLSX_ROWGUID(rowguid);
materialtrauslog.setQLSX_UPDATE_DATE(updatedate);
materialtrauslog.setQLSX_CHANGE_FLAG(changeFlag);
//获取MATERIALS节点
Node nodeMaterials = document.selectSingleNode("/DATAAREA/MATERIALS");
//取得MATERIALS节点下所有名为“MATERIAL”的子节点,并进行遍历. 遍历后每一个元素就是一组 MATERIAL 标签中的值
List listMaterial = ((Element) nodeMaterials).elements("MATERIAL");
for (Iterator it = listMaterial.iterator(); it.hasNext();) {
Element elmMaterial = (Element) it.next(); // 获取一个 MATERIAL 节点
//提前取出materialRes、materialGuid,供下面material_res复用
String materialRes = elmMaterial.element("MATERIAL_RES").getText();
String materialGuid = elmMaterial.element("MATERIALGUID").getText();
MaterialInfo materialInfo = new MaterialInfo();
materialInfo.setMATERIALGUID(materialGuid);
materialInfo.setQLSX_ROWGUID(rowguid);
materialInfo.setQLSX_UPDATE_DATE(updatedate);
materialInfo.setNAME(elmMaterial.element("NAME").getText());
materialInfo.setFORMAT(elmMaterial.element("FORMAT").getText());
materialInfo.setDETAIL_REQUIREMENT(elmMaterial.element("DETAIL_REQUIREMENT").getText());
materialInfo.setNECESSITY(elmMaterial.element("NECESSITY").getText());
materialInfo.setNECESSITY_DESC(elmMaterial.element("NECESSITY_DESC").getText());
materialInfo.setIS_RQ(elmMaterial.element("IS_RQ").getText());
materialInfo.setBAK(elmMaterial.element("BAK").getText());
listInfo.add(materialInfo);
/*
* EMPTYTABLE EXAMPLETABLE 标签(可能有多个)下 均有FILENAME、FILECONTENT、FILEURL子标签,
* 会产生多个数据,遍历后在每一个数据下再进行bean的创建封装,以对应每一条记录。
*/
List listEmptytable = elmMaterial.elements("EMPTYTABLE");
for (Iterator it2 = listEmptytable.iterator(); it2.hasNext();) {
Element elmEmptytable = (Element) it2.next(); // 获取一个 EMPTYTABLE 节点
MaterialRes materialres = new MaterialRes();
materialres.setMATERIALGUID(materialGuid);
materialres.setMATERIAL_RES(materialRes);
materialres.setEXAMPLETABLE(EnumNumber.NUMZERO.getNumber()); //枚举类型 值为0
materialres.setFILENAME(elmEmptytable.element("elmEmptytable").getText());
materialres.setFILECONTENT(elmEmptytable.element("FILECONTENT").getText());
materialres.setFILEURL(elmEmptytable.element("FILEURL").getText());
listRes.add(materialres);
}
List listExampletable = elmMaterial.elements("EXAMPLETABLE");
for (Iterator it3 = listExampletable.iterator(); it3.hasNext();) {
Element elmExampletable = (Element) it3.next(); // 获取一个 EXAMPLETABLE 节点
MaterialRes materialres = new MaterialRes();
materialres.setMATERIALGUID(materialGuid);
materialres.setMATERIAL_RES(materialRes);
materialres.setEXAMPLETABLE(EnumNumber.NUMONE.getNumber()); //枚举类型 值为1
materialres.setFILENAME(elmExampletable.element("elmEmptytable").getText());
materialres.setFILECONTENT(elmExampletable.element("FILECONTENT").getText());
materialres.setFILEURL(elmExampletable.element("FILEURL").getText());
listRes.add(materialres);
}
}
//返回封装好的数据集合
XmlParserVO xmlparservo = new XmlParserVO(listRes, listInfo, materialtrauslog);
return xmlparservo;
我把一些细节以及修改在代码中用注释进行了标注,以便于理解。
小细节:
①枚举类型的使用,而不是直接给值1或者0,枚举的好处在此不再赘述。【我也是被经理指出后的建议才修改的】,其实这里可以直接就在本类中定义常量的形式代替枚举,因为别的地方也没有用到。总之不要直接在代码中去写“0”这一类的代码。目的是为了以后便与修改。
②最后返回数据用 数据传输对象 封装返回。
③ 变量命名规范,我个人的坏毛病总是喜欢用下划线,在这里强调下能用驼峰别用下划线,推荐安装阿里的java开发规范插件,代码至少要做到工整,还有,注释要完整,比如我经常会忘记在方法的注释中只写个简洁的说明,而不写参数@param等注释,这样很不规范严谨,给后来的开发者维护带来困难。
对返回的集合遍历取出bean,作为object参数传入dao,进行数据库插入:
[java] view plain copy
<code class="language-java">@SuppressWarnings("rawtypes")
public class GetMaterialInfoDao extends HibernateEntityDao {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
super.sessionFactory = sessionFactory;
}
@SuppressWarnings("unchecked")
@Transactional
public void saveDate(Object obj){
Session session = sessionFactory.getCurrentSession();
session.save(obj);
}
}</code>
这段代码其实就是我不会用hibernate的体现。-save()方法还用在dao层自己写吗??? ̄□ ̄||
功能逻辑上到此就完成了。但是因为一些细节,导致一直在不断修改,也算是踩坑记录吧。
1、当数据存入新建的表之后,要把 AAAA 表中已经取出并入库的该条数据的process字段从0 改为1 ,来标志着该条数据记录已经完成取值入库的处理流程。一开始我是用rowguid和update_date两个字段参数去 AAAA 表更新process字段,但是经理说我逻辑不对,为什么?我用做更新process字段传递的这两个参数rowguid和update_date值,来自于最开始从 AAAA 中取回xml数据时的那个查询语句,这个update_date 是取得最大值【max(UPDATE_DATE) UPDATE_DATE】,如果我还用这个update_date做参数去定位数据记录,那么我只能更新 AAAA 表中该rowguid下rowguid相同,update_date最大的那条数据的process,其他的给漏掉了。比如:
---------------------------------------------------------
rowguid | update_date |process
12 | 2017-08-13 | 0 ---------------也应该改为1,但被漏掉了
12 | 2017-08-14 | 0 ---------------也应该改为1,但被漏掉了
12 | 2017-08-15 | 0 ---------------改为 1
开发过程中考虑的不严谨不周全,【关于这一点,还有,在把解析出的数据存入库之前,再做一个验证,去material_info表里面查询一下这条数据是否已经存在,如果已存在,删了,再把现在刚解析出的数据插入进去,这一点也是我不曾考虑到的】,虽然对业务流程不熟悉,毕竟只是单一接到功能需求,大范围业务流程背景并不清楚,但是严谨周全的工作思路还是必须的。不然就是一堆bug了。。。。
2、 在最开始从 AAAA 表中取数据时,内存溢出异常。三十万条数据,我直接就一次取出放入list接收了,根本就没有考虑可行的意识,只是直接认为这样能实现功能,还是在实现功能的层面去开发。肯定要分页去查询了啊(mysql limit)。改进的过程中,先获取总记录数,定义一次查多少条,计算查询出次数,然后分页 limit 查询 。再从另外一角度考虑下,为什么不在这里加一个多线程去执行,这样不是更快吗,现在肯定很慢。再次改进,代码如下:
------------------------------------添加 线程 并 分页 从 _new表 查询 xml 等数据 代码---------------------------------
private static final int LIMIT = 50;
private final static Executor executor = Executors.newCachedThreadPool();//启用多线程
@Override
public void dataHanding() {
Long countNum = qltQlsxDao.getCountNum();
int times = 0;
if( 0 == countNum % LIMIT ){
times = (int) (countNum / LIMIT);
}else{
times = (int) (countNum / LIMIT) +1;
}
//int times = (int) Math.floor(countNum / LIMIT);
//分页查询 避免内存溢出
for (int i = 1; i <= times; i++) {
// List<QltQlsxNewDto> dataLst = qltQlsxDao.getMaterialInfo((i - 1) * LIMIT, LIMIT);
// if ( null == dataLst || dataLst.isEmpty() ) {
// logger.info("无数据需要处理");
// return ;
// }
final int j=i;
executor.execute(new Runnable() {
@Override
public void run() {
try{
List<QltQlsxNewDto> dataLst = qltQlsxDao.getMaterialInfo((j - 1) * LIMIT, LIMIT);
if ( null == dataLst || dataLst.isEmpty() ) {
logger.info("无数据需要处理");
return ;
}
parseXMLInfoAndSave(dataLst);
}catch(Exception e){
}
}
});
}
}
经过实际测试,速度比原来快的多得多。参考:http://blog.csdn.net/bestcxx/article/details/49472035
----------------------------------------------------代码完 分割线---------------------------------------------------------------
3、关于上面的limit,给dao层sql语句穿两个参数,一个是开始取值的下标m,一个是每次取多少个n,其实就是limit 的两个参数 limit m,n
如果最后一次分页,未取数据剩余数目小于 n,这是没关系的,不受影响。最后一次分页剩45个数据没取,我每次都取50,也不会报错的啊。可我犯糊涂了,进行判断是不是最后一次的分页,是的话,就把传的参数n改为经过计算得出的最后还没取出的数目,比如 limit(m,45)。
4、还是关于代码的编写,尽量进行封装复用。
比如上面xml解析代码中的
materialInfo.setDETAIL_REQUIREMENT(elmMaterial.element("DETAIL_REQUIREMENT").getText());
更改后把
elmMaterial.element("DETAIL_REQUIREMENT").getText()
放到一个方法中去,
// 封装从Node中获取Element,并获取Text
private String getElementAsText(Element e, String nodeName ) {
Element targetElement = e.element(nodeName);
if ( null == targetElement ) return null;
return targetElement.getText();
}
5、注解事务 改为 手动事务
这个要看具体场景灵活选择。如果使用注解在方法A上,A中又调用方法B,B里面其中 x部分的代码次啊是真正想要进行事务控制的地方,就这x处手动开启 运用事务,而我之前只是简单的把事务注解放在A上面完事,压根就没有考虑这个方面的问题。。。。
session.beginTransaction();
xxxxxxxxxxxxxxxxxxxxxxx;
session.getTransaction().commit();
6、在新建dao层service层时,注意为以后的业务扩展考虑,不同表的增删改查操作方法不要写在一个dao里面,按照业务新建dao。其它层次也是同理。说到这想起了之前在北京的一位同事,当时给我讲解传参的场景,客户需求总是变来变去,有时候参数传递自己不要写的那么死,给自己留条路,便于自己修改,也利于项目代码优化。
在此,真心向给与我过知道帮助的同事朋友说一声谢谢。ღ( ´・ᴗ・` )比心
没有什么特别大的高深内容,但都是我每一步菜的坑和小结心得吧,警醒自己吸取教训,努力进步。
解析xml数据存入bean映射到数据库的 需求解决过程的更多相关文章
- 【iOS-cocos2d-X 游戏开发之九】Cocos2dx利用CCSAXParser解析xml数据&CCMutableDictionary使用与注意!
本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2dx/694.html ☞ ...
- xml数据文件上传至数据库
上传xml文件数据到数据库思路:首先上传需要建校验xml字段的校验文件,然后程序根据后台写好的xml数据文件路径自动读取数据文件,再上传数据文件到数据库之前先根据校验文件校验上传的数据文件的字段是否合 ...
- iOS解析XML数据
iOS中解析XML数据的类是 NSXMLParser,详细使用方法如下: 假设现在在内存中有XML的二进制数据对象(NSData):data(该数据可能来自网络,也可能是本地的文件数据),设置NSX ...
- Android网络之数据解析----SAX方式解析XML数据
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- 160928、JQuery解析XML数据的demo
用JavaScript解析XML数据是常见的编程任务,JavaScript能做的,JQuery当然也能做.下面我们来总结几个使用JQuery解析XML的例子. 方案1 当后台返回的数据类型是xml对象 ...
- JQuery解析XML数据的几个例子
用JavaScript解析XML数据是常见的编程任务,JavaScript能做的,JQuery当然也能做.下面我们来总结几个使用JQuery解析XML的例子. 第一种方案: <script ty ...
- (四)SAX方式解析XML数据
SAX方式解析XML数据 文章来源:http://www.cnblogs.com/smyhvae/p/4044170.html 一.XML和Json数据的引入: 通常情况下,每个需要访问网络的应用程 ...
- 导入libxml.dylib用Google的GDataXML解析XML数据
1.用Google的GDataXML来解析XML数据,导入libxml.dylib 2.导入libxml.dylib的操作实现,一开始自己总是找不到libxml.dylib文件. 选择其他文件,到路径 ...
- 【Android Developers Training】 81. 解析XML数据
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
随机推荐
- UIPasteboard
1.UIPasteboard 简介 顾名思义,UIPasteboard 是剪切板功能,因为 iOS 的原生控件 UITextField.UITextView.UIWebView, 我们在使用时如果长按 ...
- slice()、substring()、substr()的区别用法
在js中字符截取函数有常用的三个slice().substring().substr()了,下面我来给大家介绍slice().substring().substr()函数在字符截取时的一些用法与区别吧 ...
- 洛谷P3674 小清新人渣的本愿(莫队)
传送门 由乃tql…… 然后抄了一波zcy大佬的题解 我们考虑把询问给离线,用莫队做 然后用bitset维护,每一位代表每一个数字是否存在,记为$now1$ 然后再记录一个$now1$的反串$now2 ...
- Oracle数据控制语言(DCL)
数据控制语言 用来授予或者回收访问数据库中的各种对象,如表 .视图 .索引 等 基本的操作如下: --创建用户 CREATE USER jim IDENTIFIED BY changeit; --给用 ...
- loj#6229 这是一道简单的数学题
\(\color{#0066ff}{ 题目描述 }\) 这是一道非常简单的数学题. 最近 LzyRapxLzyRapx 正在看 mathematics for computer science 这本书 ...
- 模板 ST表
ST表 询问静态最值. code: #include <iostream> #include <cstdio> using namespace std; inline int ...
- Leetcode 121. Best Time to Buy and Sell Stock 最佳股票售卖时(动态规划,数组,模拟)
题目描述 已知一个数组,第i个元素表示第i天股票的价格,你只能进行一次交易(买卖各一次),设计算法找出最大收益 测试样例 Input: [7, 1, 5, 3, 6, 4] Output: 5 最大收 ...
- Glassfish Password Alias
https://docs.oracle.com/cd/E19798-01/821-1751/ghgqc/index.html
- CF986B Petr and Permutations 思维
每次交换:逆序对的数量+1或者-1: 假设最后逆序对数量为 sum; ①x+y=3n; ②x-y=sum; -> 3n+sum为偶数: 所以 n 和 sum 必须奇偶一样: #include&l ...
- Subversion Server Edge的安装使用
1.Subversion Server Edge的搭建 当在操作系统为64位的配置服务器上部署时只能够选择Collabnet Subversion Edge,它集合了Subversion所需要一切资源 ...