0%

为什么我们要用Lucene?
Lucene 仅仅是在网站内部进行文本的搜索,我们也可以sql来进行站内的搜索。
sql搜索和Lucene对比:

1.去官网下载pdf.js。
其中的view.html不要改,直接放在jsp里。
view.js是渲染pdf,下面的方法需要注意的是路径要对。之前文件流已获得,但是渲染不出来就是因为这里路径不对。

1
2
3
4
5
6
function configure(PDFJS) {
PDFJS.imageResourcesPath = path +’resources/ctrl/pdfjs/web/images/’;
PDFJS.workerSrc = path +’resources/ctrl/pdfjs/build/pdf.worker.js’;
PDFJS.cMapUrl = path +’resources/ctrl/pdfjs/web/web/cmaps/’;
PDFJS.cMapPacked = true;
}

2.修改viewer.js
var DEFAULT_URL = ‘compressed.tracemonkey-pldi-09.pdf‘ 里面是PDF的路径删除该变量定义;

3.ajax调用
写在view.js开头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var path = $(“base”).attr(“href”);
var PDFData = “”;
$.ajax({
type: “GET”,
async: false, //
//dataType: “text”,
mimeType: ‘text/plain; charset=x-user-defined’,
url: path+”pdf”,//这里是读取的文件流
success: function(data) {
PDFData = data; //data就是byte[]数组,下面有介绍
}
});
var rawLength = PDFData.length;
//转换成pdf.js能直接解析的Uint8Array类型,见pdf.js-4068
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (var i = 0;i < rawLength; i++) {
array[i] = PDFData.charCodeAt(i) & 0xff;
}
DEFAULT_URL = array;

方法一:
1.本地文件流后台处理,只用了web项目,没有任何框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void pdfStreamHandeler(HttpServletRequest request, HttpServletResponse response) {
filePath = “d://a.pdf”;
File file = new File(filePath);
byte[] data = null;
try {
FileInputStream input = new FileInputStream(file);
data = new byte[input.available()];
input.read(data);
response.getOutputStream().write(data);
input.close();
} catch (Exception e) {
logger.error(“pdf文件处理异常:” + e.getMessage());
}
}

方法二:跨域(从云服务器下载)设计知识点(https://www.alibabacloud.com/help/zh/doc-detail/32016.htm?spm=a3c0i.o32014zh.b99.108.e7882928dW9FL)

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
@RequestMapping(value = “/pdf”, method = RequestMethod.GET)
@ResponseBody
public byte[] loadPdf1(Model model, HttpServletResponse response, HttpServletRequest request) {
final String keySuffixWithSlash = “a.pdf”;
// 创建OSSClient实例
OSSClient Server = new OSSClient(endpoint, accessKeyId, accessKeySecret);
Date expiration = new Date(new Date().getTime() + 3600 * 1000);
GeneratePresignedUrlRequest request1 = new
GeneratePresignedUrlRequest(“aaa”, keySuffixWithSlash,
HttpMethod.GET);
// 设置过期时间
request1.setExpiration(expiration);
URL signedUrl = Server.generatePresignedUrl(request1);
String url = signedUrl.toString();
Server.shutdown();
System.out.println(“signed url for getObject: “ + signedUrl.toString());
HttpURLConnection httpConn = null;
URL urlObj;
try {
//将url转化成流,把他利用resonse读出,返回页面的是buffBytes
HttpURLConnHelper HttpURLConnHelper=new HttpURLConnHelper();
InputStream input=HttpURLConnHelper.loadFileFromURL(url);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(“application/pdf;charset=UTF-8”);
ServletOutputStream out =null;
out = response.getOutputStream();
int read = 0;
byte buffBytes[] =new byte[1024];
while((read = input.read(buffBytes)) != -1) {
out.write(buffBytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return null;
}

其中HttpURLConnHelper是一个方法类,使用了别人的工具类

步骤一:使用Maven进行Jar包的管理,使用的jar包如下:

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
<!– quartz 的jar –>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<!– spring相关jar –>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<!– 日志相关jar包 –>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
</dependency>
<dependency><!– Failed to load classorg.slf4j.impl.StaticLoggerBinder”. –>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<!– MySql的包 –>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.31</version>
</dependency>

步骤二:任务job

1
2
3
4
5
6
7
8
public class HelloWorldJob implements Job{
private Logger log = LoggerFactory.getLogger(this.getClass());
public void execute(JobExecutionContext arg0) throws JobExecutionException {
log.info(“This is a first spring combine quartz !”);
log.info(“Welcome to Spring_Quartz World!”+ new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date()) );
log.info(“Let’s begin ! \n \n”);
}
}

步骤三:
启动程序

1
2
3
4
5
public class HWTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“spring_quartz.xml”);
}
}

步骤四:配置文件spring_quartz.xml
(1):配置文件

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
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”;
xmlns:context=”http://www.springframework.org/schema/context”; xmlns:p=”http://www.springframework.org/schema/p”;
xmlns:aop=”http://www.springframework.org/schema/aop”; xmlns:tx=”http://www.springframework.org/schema/tx”;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”;
xsi:schemaLocation=”http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsd”>;
<!–
Spring整合Quartz进行配置遵循下面的步骤:
1:定义工作任务的Job
2:定义触发器Trigger,并将触发器与工作任务绑定
3:定义调度器,并将Trigger注册到Scheduler
–>
<!– 1:定义任务的bean ,这里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置类似–>
<bean name=”hwJob” class=”org.springframework.scheduling.quartz.JobDetailFactoryBean”>
<!– 指定job的名称 –>
<property name=”name” value=”hw_job”/>
<!– 指定job的分组 –>
<property name=”group” value=”hw_group”/>
<!– 指定具体的job类 –>
<property name=”jobClass” value=”com.dufy.spring.quartz.chapter01.job.HelloWorldJob”/>
<!– 必须设置为true,如果为false,当没有活动的触发器与之关联时会在调度器中会删除该任务 –>
<property name=”durability” value=”true”/>
<!– 指定spring容器的key,如果不设定在job中的jobmap中是获取不到spring容器的 –>
<property name=”applicationContextJobDataKey” value=”applicationContext”/>
</bean>
<!– 2.1:定义触发器的bean,定义一个Simple的Trigger,一个触发器只能和一个任务进行绑定 –>
<!– <bean name=”simpleTrigger” class=”org.springframework.scheduling.quartz.SimpleTriggerFactoryBean”>
指定Trigger的名称
<property name=”name” value=”hw_trigger”/>
指定Trigger的名称
<property name=”group” value=”hw_trigger_group”/>
指定Tirgger绑定的Job
<property name=”jobDetail” ref=”hwJob”/>
指定Trigger的延迟时间 1s后运行
<property name=”startDelay” value=”1000″/>
指定Trigger的重复间隔 5s
<property name=”repeatInterval” value=”5000″/>
指定Trigger的重复次数
<property name=”repeatCount” value=”5″/>
</bean> –>
<!– 2.2:定义触发器的bean,定义一个Cron的Trigger,一个触发器只能和一个任务进行绑定 –>
<bean id=”cronTrigger” class=”org.springframework.scheduling.quartz.CronTriggerFactoryBean”>
<!– 指定Trigger的名称 –>
<property name=”name” value=”hw_trigger”/>
<!– 指定Trigger的名称 –>
<property name=”group” value=”hw_trigger_group”/>
<!– 指定Tirgger绑定的Job –>
<property name=”jobDetail” ref=”hwJob”/>
<!– 指定Cron 的表达式 ,当前是每隔1s运行一次 –>
<property name=”cronExpression” value=”0/1 * * * * ?” />
</bean>
<!– 3.定义调度器,并将Trigger注册到调度器中 –>
<bean id=”scheduler” class=”org.springframework.scheduling.quartz.SchedulerFactoryBean”>
<property name=”triggers”>
<list>
<!– <ref bean=”simpleTrigger”/> –>
<ref bean=”cronTrigger”/>
</list>
</property>
<!– <property name=”autoStartup” value=”true” /> –>
</bean>
</beans>

文件流分步读取(可以结合印象笔记来看)
1.将文件全部读出来,记录一个最大值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String file_name = “C:\\Users\\Administrator\\Desktop\\365函数转换\\365函数转换\\HC_170727HK030507_20171025231202.ECD”;
File file = new File(file_name);
if (!file.exists()) {
return;
}
FileInputStream fis=null;
String[] fileArray=file.getName().split(“\\.”);
FileOutputStream fos=null;
decode256.init();
//这里是写出的文件流
fos=new FileOutputStream(new File(“C:\\Users\\Administrator\\Desktop\\365函数转换\\365函数转换”,fileArray[0]+“.256”));
//将文件写入
fis = new FileInputStream(file);
int datLength=fis.available(); //文件的长度
//先读取1200个字节
byte[] ecgByte = new byte[1200];
while(readLength=fis.read(ecgByte)) != -1){ //如果不是最后一个就一直读

2.这里就是一直对读出的文件进行操作(不要多余最大值)

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
for (int i=0; i < readLength;i++) {
int ecg_wk32 = decode256.eCGBuild(ecgByte[i] & 0x000000ff);
chdt11 = chdt1;
chdt22 = chdt2;
chdt1 = ecg_wk32 / 65536; // 得到1通道16位数据
chdt2 = ecg_wk32 & 65535;
while (jj <= position) {
fdatava = index / F2 * F1;

jj = (long) Math.floor(fdatava);
fdatava = fdatava – jj;
BLE1.add((int)(chdt11+Math.floor((chdt1–chdt11)*fdatava)));
BLE2.add((int)(chdt22+Math.floor((chdt2–chdt22)*fdatava)));
index++;
}
position++;
}
//将读出的文件转成byte
ECGCH12=new byte[BLE2.size()*6];
for(int i=0,j=0;j<BLE2.size();j++) {
ECGCH12[i]= (byte) (BLE1.get(j)&0xff);
ECGCH12[++i]=(byte) ((BLE1.get(j) / 256)&0xff);
ECGCH12[++i]= (byte) (BLE2.get(j)&0xff);
ECGCH12[++i]= (byte) ((BLE2.get(j)/256)&0xff);
kk = BLE2.get(j)- BLE1.get(j)+500;
ECGCH12[++i]= (byte) (kk&0xff);
ECGCH12[++i]= (byte) ((kk / 256)&0xff);
i++;

}
  1. 最后写进入流里,只要不关闭,就一直写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{  
fos.write(ECGCH12);

BLE2.clear();
BLE1.clear();

}catch (Exception e) {
e.printStackTrace();
} finally {
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null) {
try {
fos.close();
} catch (Exception e2) {
}

}
}

1.文件流的使用
1.1读取文件,转化成流
获取当前路径,创建file,把file写进流里,建立byte数组,直接写进流里

1
2
3
4
5
6
file file =new File(String path);
if(!file.exist()){
return;
}
inputSteam input=new inputstream(file);
int datLength=fis.available(); //文件的长度

获取文件的长度
直接写进byte数组

1
2
3
4
byte[] ecgByte = new byte[datLength];
while(readLength=fis.read(ecgByte)) != -1){ //如果不是最后一个就一直读
fos.write(ecgByte);
}

上传图片
看工具包upserver

1
2
3
4
5
6
7
8
<!– quartz –>
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency><dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version></dependency>
步骤一:
public class RAMJob implements Job{
@Override public void execute(JobExecutionContext arg0) throws JobExecutionException {
//这里是你要执行什么,关键代码,如订单取消订单
_log.info(“Say hello to Quartz” + new Date());
}

步骤二:

1
2
3
4
5
6
7
8
9
10
11
12
public class RAMQuartz {
private static Logger _log = LoggerFactory.getLogger(RAMQuartz.class);
public static void main(String[] args) throws SchedulerException {
//1.创建Scheduler的工厂
SchedulerFactory sf = new StdSchedulerFactory();
//2.从工厂中获取调度器实例
Scheduler scheduler = sf.getScheduler();
//3.创建JobDetail
JobDetail JobDetail = JobBuilder.newJob(RAMJob.class)
.withDescription(“this is a ram job”) //job的描述
.withIdentity(“ramJob”, “ramGroup”) //jobnamegroup
.build();

说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!– 指定job的名称 –> 
<property name=“name” value=“hw_job”/>
<!– 指定job的分组 –>
<property name=“group” value=“hw_group”/>
//任务运行的时间,SimpleSchedle类型触发器有效
long time= System.currentTimeMillis() + 3*1000L; //3秒后启动任务
Date statTime = new Date(time);
//4.创建Trigger
//使用SimpleScheduleBuilder或者CronScheduleBuilder
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription(“”)
.withIdentity(“ramTrigger”, “ramTriggerGroup”)
//.withSchedule(SimpleScheduleBuilder.simpleSchedule())
.startAt(statTime) //默认当前时间启动
.withSchedule(CronScheduleBuilder.cronSchedule(“0/2 * * * * ?”)) //两秒执行一次
.withSchedule(这里是触发器类型);
.build();
//5.注册任务和定时器
scheduler.scheduleJob(JobDetail, trigger);
//6.启动 调度器
scheduler.start();
_log.info(“启动时间 : ” + new Date());
}
}

1:註冊個sourtree
2:登錄gitLab
3:生成密匙
https://www.cnblogs.com/xiuxingzhe/p/9303278.html
4:工具-選項
設置用戶名 電子郵箱
設置ssh客戶端配置:
ssh密匙:.ppk
ssh客戶端
5:這裡說的是gitLab設置了密匙,如果沒有就不要設置了
特別說明一下:
大家在使用mac时候,很多时候发现,svn上不能使用window用惯的ppk文件,需要转换。以下介绍windows转换过程:

条件:1、要有puttygen.exe 2、要有一个ppk文件

方法,

1、双击击puttygen.exe ->conversions ->import Key

2、conversions ->exportOpenSSH

這裡導入的ppk,就是第四點說的

我們一般說的是線程等待。
例子:(以b為主)
1:a等待b,b等待c,c又等待d.
2:b是執行自己的應用,但是報錯了,導致下面的程序沒法走,所以又在等待。
主要發佈在:
1:查詢數據庫
2:redis集群崩潰
3:查詢mysql和訪問redis最大值,最後就佔用線程,最後沒法預留。
解決:
1:雙機部署,分開兩個機房
2:進行數據庫同步數據
具體發生了:
對 緩存 使用了熔斷(就像初中說的自動斷電保險絲,比如當電壓太高了,進行自動斷電,保護因為電流燒掉),降級處理。
熔斷(springcloud里的)
當出現線程錯誤,然後就開始在等待,有個規定的時間,如果超過90秒沒有像服務器註冊,那麼註冊中心就認為這個服務不可用。
然後就開啟熔斷,然後也把和這個相關的程序進行降級,減少他的訪問次數。如果當他正常,就關閉熔斷。
對原服務進行限流,資源隔離。
處理后:
Redis數據備份和回復
快速緩存預熱

参考链接:https://www.cnblogs.com/jifeng/p/4676863.html

放进去一个key_values,但是实际中作用不大
下面是一个set例子:这个模板和jedis是一样的。如果有不明白的,可以看菜鸟教程的命令
测试类放入工具包
接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface RedisService {
//通过key删除
public long del_set(String keys,byte[] values);
//添加key value 并且设置存活时间(byte)
public void set_set(byte[] key, byte[] value, long liveTime);
//获取集合的长度
public long dbSize();
//清空redis 所有数据
public abstract String flushDB();

public Set<byte[]> getList_set();

}

实现类:

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
@Service(value = “redisService”)
public class RedisServiceImpl implements RedisService{
private static String redisCode = “utf-8”;

@Autowired
private RedisTemplate redisTemplate;
//删除方法
public long del_set(final String keys,final byte[] values) {
System.out.println(“del”);
return (Long) redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Long result = connection.sRem(“user”.getBytes(), values);
return result;
}
});
}
public void set_set(final byte[] key, final byte[] value, final long liveTime) {
System.out.println(“set”+key+” “+value);
redisTemplate.execute(new RedisCallback<Boolean>(){
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
//集合
connection.sAdd(key, value);
System.out.println(“设置成redis成功”);
return true;
}
});
}
/**
* @return
*/
public long dbSize() {
System.out.println(“dbSize”);
return (Long) redisTemplate.execute(new RedisCallback() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.sCard(“user”.getBytes());
}
});
}
/**
* @return 清空里面的记录
*/

public String flushDB() {
System.out.println(“flushDB”);
return (String) redisTemplate.execute(new RedisCallback() {
public String doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return “ok”;
}
});
}

public Set<byte[]> getList_set() {
//final List<User> list=new ArrayList<User>();
return (Set<byte[]>) redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
String key=“user”;
Set<byte[]> bytes=connection.sMembers(key.getBytes());
return bytes;

}
});

}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 ApplicationContext app = new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
RedisService redisService = (RedisService) app.getBean(“redisService”);
//这个是用于把set的集合变成对象
@Test
public void test2() {
try {
Set<byte[]> userList=redisService.getList_set();
List<User> list=new ArrayList<User>();
for(byte[] bytes:userList) {
User user=(User) SerializeUtils.deSerialize(bytes);
list.add(user);
}
for(User user:list) {
System.out.println(user.getId());
}
System.out.println(redisService.dbSize());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

xml配置文件:

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
<?xml version=“1.0” encoding=“UTF-8”?>
<beans xmlns=“http://www.springframework.org/schema/beans”;
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”;
xmlns:p=“http://www.springframework.org/schema/p”;
xmlns:aop=“http://www.springframework.org/schema/aop”;
xmlns:context=“http://www.springframework.org/schema/context”;
xsi:schemaLocation=“http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd “>

<context:component-scan base-package=“com.dh.service”>
<context:exclude-filter type=“annotation”
expression=“org.springframework.stereotype.Controller” />
</context:component-scan>
<bean id=“connectionFactory” class=“org.springframework.data.redis.connection.jedis.JedisConnectionFactory”>
<property name=“hostName” value=“127.0.0.1” />
<property name=“port” value=“6379” />
<!– <property name=”password” value=”${redis.password}” /> –>
</bean>

<bean id=“redisTemplate” class=“org.springframework.data.redis.core.RedisTemplate” >
<property name=“connectionFactory”>
<ref bean=“connectionFactory”/>
</property>
</bean>

1.get和load()区别是什么?
get和load的最大区别是,如果在缓存中没有找到相应的对象,get将会直接访问数据库并返回一个完全初始化好的对象,而这个过程有可能会涉及到多个数据库调用;而load方法在缓存中没有发现对象的情况下,只会返回一个代理对象,只有在对象getId()之外的其它方法被调用时才会真正去访问数据库,这样就能在某些情况下大幅度提高性能。

2.Hibernate中save、persist和saveOrUpdate这三个方法的不同之处?
save()只能INSERT记录,但是saveOrUpdate()可以进行 记录的INSERT和UPDATE。还有,save()的返回值是一个Serializable对象,而persist()方法返回值为void。你还可以访问 save、persist以及saveOrUpdate,找到它们所有的不同之处。

3.Hibernate中的SessionFactory有什么作用? SessionFactory是线程安全的吗?
SessionFactory就是一个用于创建Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全的,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是 不可变的,一旦创建好后就不能对其进行修改了。

4.Hibernate中的Session指的是什么? 可否将单个的Session在多个线程间进行共享?
Session代表着Hibernate所做的一小部分工作,它负责维护者同数据库的链接而且 不是线程安全的,也就是说,Hibernate中的Session不能在多个线程间进行共享。虽然Session会以主动滞后的方式获得数据库连接,但是Session最好还是在用完之后立即将其关闭。

2018年已经是出校门学习java的差不多一年左右了,自己在公司熟悉业务流程和写代码已经有些日子了,为了更多的 money,要努力学习。

大神的脚步走的很快,我们是只能算个码农,为此不努力不行。只能跟着大神边学习,边工作。

2018学习目标如下:

1.学习spring,hibernate,mybaits,springmvc的原理。

2.学习微信支付,支付宝支付等,要是可以,尽量动手做。

3.设计模式的学习,java10特性的学习。

4.springcloud,springboot能够知道如何使用,配置

5.学习高并发,分步式的知识。(以淘淘商城为例,掌握原理和运用)

争取在2018年工资翻一翻,跟着大神走,不会错。。。。。。。。。。。。。。。。。。。。。。。。。。。

RestTemplate定義了36個Rest資源交互的方法,其中的大多數都對應于http的方法。
delete() 在特定的URL上对资源执行HTTP DELETE操作

exchange()
在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中
映射得到的

execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象

getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象

getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象

postForEntity()
POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得
到的

postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象

headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头

optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息

postForLocation() POST 数据到一个URL,返回新创建资源的URL

put() PUT 资源到特定的URL

getForEntity說明:
基本的形式

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
/**
* @author itguang
* @create 2017-12-17 10:37
**/
@RestController
public class UserController {

@Autowired
private UserService userService;

@RequestMapping(value = “getAll”)
public List<UserEntity> getUser() {
List<UserEntity> list = userService.getAll();
return list;
}

@RequestMapping(“get/{id}”)
public UserEntity getById(@PathVariable(name = “id”) String id) {

return userService.getById(id);
}
@RequestMapping(“get/{id}/{type}”)
public UserEntity getByIdAndType(@PathVariable(name = “id”) String id,String type) {

return userService.getByIdAndType(id,type);
}

@RequestMapping(value = “save”)
public String save(UserEntity userEntity) {

return “保存成功”;
}


@RequestMapping(value = “saveByType/{type}”)
public String saveByType(UserEntity userEntity,@PathVariable(“type”)String type) {

return “保存成功,type=”+type;
}


}

改變的:

1
2
3
4
5
6
7
8
9
10
11
12
@RequesyMapping(“getForEntity”)
public List<UserEntity> getAll2(){
ResponseEntity<List> responseEntity = restTemplate.getForEntity(“http://localhost/getAll”,List.class);
HttpHeaders headers = responEntity.getHeaders();
HttpStatus statusCode = responseEntity.getStatusCode();
int code = statusCode.value();

List<UserEntity> list = responseEntity.getBody();

System.out.println(list.toString());
return list;
}

有參數的:

1
2
3
4
5
6
7
@RequestMapping(“getForEntity/{id}”)
public UserEntity getById(@PathVariable(name = “id”) String id) {

ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity(“http://localhost/get/{id}”, UserEntity.class, id);
UserEntity userEntity = responseEntity.getBody();
return userEntity;
}

參數多的情況:

1
2
3
4
5
6
7
8
9
@RequestMapping(“getForEntity/{id}/{type}”)
public UserEntity getById(@PathVariable(name = “id”) String id,@PathVariable(name = “type”) Stringtype) {
Map map = new HashMap();
map.put(“id”,id);
map.put(“type”, type);
ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity(“http://localhost/get/{id}/{type}”, UserEntity.class,map);
UserEntity userEntity = responseEntity.getBody();
return userEntity;
}

getForObject 和 getForEntity 用法几乎相同,指示返回值返回的是 响应体,省去了我们 再去 getBody() .getForObject都是service是什麼類型,就是獲取的是什麼類型。
測試getForObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public List<UserEntity> getAll(){
List<UserEntity> list=restTemplate.getForObject(“http://localhost/getAll”,List.class);
System.out.println(list.toString());
return list;
}
// 有参数的 postForEntity 请求,使用map封装
@RequestMapping(“saveUserByType2/{type}”)
public String save3(UserEntity userEntity,@PathVariable(“type”)String type) {
HashMap<String, String> map = new HashMap<>();
map.put(“type”, type);

ResponseEntity<String> responseEntity = restTemplate.postForEntity(“http://localhost/saveByType/{type}”, userEntity, String.class,map);
String body = responseEntity.getBody();

return body;

}

redis不支持直接将java对象存储到数据库中,所以需要将java对象进行序列化得到字节数组,然后将字节数组存在redis中,需要数据时候就从redis中取出字节数组,再经过反序列化将自己数组转化成对象使用。
下面的反序列化和序列化工具类

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
public class SerializeUtils {
//将obj转成byte[]数组 序列化
public static byte[] serialize(Object obj) {
byte[] bytes = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
;
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
bytes = baos.toByteArray();
baos.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
//将byte[]数组转成obj 反序列化
public static Object deSerialize(byte[] bytes){
Object obj=null;
try {
ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
ObjectInputStream ois=new ObjectInputStream(bais);
obj=ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}

下面简单测试:

1
2
3
4
5
6
7
8
9
10
//获取链接
Jedis jedis=JedisUtil.getJedis();
//创建对象
User user=new User(“1000”, “宝宝”, “xioabao”);
//把一个对象存入进去,其中id作为key,后面的对象序列化成byte字节
jedis.set(user.getId().getBytes(), SerializeUtils.serialize(user));
//先取出key,再取出values 从redis取出来将序列化的数组转成对象
byte[] bytes=jedis.get(user.getId().getBytes());
System.out.println((User)SerializeUtils.deSerialize(bytes));
jedis.close();

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
<!–********************************************配置hibernate********************************************–>

<!–扫描配置文件(这里指向的是之前配置的那个config.properties)–>
<context:property-placeholder location=”classpath:/config.properties” />

<!–配置数据源–>
<bean id=”dataSource” class=”com.mchange.v2.c3p0.ComboPooledDataSource” destroy-method=”close”>
<property name=”driverClass” value=”${jdbc.driver}” /> <!–数据库连接驱动–>
<property name=”jdbcUrl” value=”${jdbc.url}” /> <!–数据库地址–>
<property name=”user” value=”${jdbc.username}” /> <!–用户名–>
<property name=”password” value=”${jdbc.password}” /> <!–密码–>
<property name=”maxPoolSize” value=”40″ /> <!–最大连接数–>
<property name=”minPoolSize” value=”1″ /> <!–最小连接数–>
<property name=”initialPoolSize” value=”10″ /> <!–初始化连接池内的数据库连接–>
<property name=”maxIdleTime” value=”20″ /> <!–最大空闲时间–>
</bean>
<!–配置session工厂–>
<bean id=”sessionFactory” class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean”>
<property name=”dataSource” ref=”dataSource” />
<property name=”packagesToScan” value=”com.ssh.entity” />
<property name=”hibernateProperties”>
<props>
<prop key=”hibernate.hbm2ddl.auto”>${hibernate.hbm2ddl.auto}</prop> <!–hibernate根据实体自动生成数据库表–>
<prop key=”hibernate.dialect”>${hibernate.dialect}</prop> <!–指定数据库方言–>
<prop key=”hibernate.show_sql”>${hibernate.show_sql}</prop> <!–在控制台显示执行的数据库操作语句–>
<prop key=”hibernate.format_sql”>${hibernate.format_sql}</prop> <!–在控制台显示执行的数据哭操作语句(格式)–>
</props>
</property>
</bean>
<!– 事物管理器配置 –>
<bean id=”transactionManager” class=”org.springframework.orm.hibernate4.HibernateTransactionManager”>
<property name=”sessionFactory” ref=”sessionFactory” />
</bean>

下面是个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.wqc.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class hbnUtils {
private static SessionFactory sessionFactory;
public static Session getSession() {

return sessionFactory.getCurrentSession();
}
public static SessionFactory getSessionFactory() {
if(sessionFactory==null ||sessionFactory.isClosed()) {
sessionFactory=new Configuration().buildSessionFactory();
}
return sessionFactory;
}
}

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
/**

* 演示Jedis连接池

* 客户端

*/

public class Demo01 {

public static void main(String[] args) {

//NO1)创建Jedis连接池配置对象,类似到c3p0-config.xml文件

JedisPoolConfig config = new JedisPoolConfig();

//NO2)创建Jedis连接池

//设置连接池最多存入10个Jedis对象

config.setMaxTotal(10);

//从连接池中取出Jedis对象最多等2秒

config.setMaxWaitMillis(2000);

//NO3)从Jedis连接池中取出一个Jedis对象

JedisPool pool = new JedisPool(config,“127.0.0.1”,6379);

//NO4)使用Jedis对象操作Redis数据库

Jedis jedis = pool.getResource();

//选择15号数据库

jedis.select(15);

//根据key找value

String username = jedis.get(“username”);

//如果value找到了

if(username != null){

//删除该key

jedis.del(“username”);

}

//NO5)将Jedis对象还回给Jedis连接池

jedis.close();

}

}

/**

* 演示通过JedisUtils来获取,操作,关闭Jedis对象

* 客户端

*/

public class Demo01 {

public static void main(String[] args) throws Exception{

//获取Jedis对象

Jedis jedis = JedisUtil.getJedis();

//使用Jedis对象操作Redis数据库

jedis.set(“address”,“长沙”);

//关闭Jedis对象

JedisUtil.close(jedis);

}

}



package com.itheima.redis.util;



import java.util.ResourceBundle;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;



/**

* Jedis工具类

*/

public final class JedisUtil {

private static JedisPool pool;

private static String maxTotal;

private static String maxWaitMillis;

private static String host;

private static String port;

/**

* 读取src/jedis.properties属性文件中的内容

*/

static{

//ResourceBundle专用于去类路径下找*.properties文件,所以扩展名properties可以不写

//建议项目中的配置文件放在src目录下

ResourceBundle rb = ResourceBundle.getBundle(“jedis”);

//根据key找value

maxTotal = rb.getString(“maxTotal”);

maxWaitMillis = rb.getString(“maxWaitMillis”);

host = rb.getString(“host”);

port = rb.getString(“port”);

}

/**

* 创建连接池对象

*/

static{

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxTotal(Integer.parseInt(maxTotal));

config.setMaxWaitMillis(Integer.parseInt(maxWaitMillis));

pool = new JedisPool(config,host,Integer.parseInt(port));

}

private JedisUtil(){

}

/**

* 获取Jedis对象

*/

public static Jedis getJedis() throws Exception{

//如果连接池非空

if(pool != null){

//从连接池中获取Jedis对象

return pool.getResource();

}else{

//return null;

//抛异常

throw new Exception(“Jedis不能为空”);

}

}

/**

* 关闭Jedis对象

*/

public static void close(Jedis jedis) {

if(jedis != null){

jedis.close();

}

}

}

3.2.1 导入JAR包

commons-pool2-2.3.jar
jedis-2.7.0.jar

3.2.2 单实例连接
代码:

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
package com.itheima.redis;


import redis.clients.jedis.Jedis;



/**

* 演示Jedis对象操作Redis内存数据库

* 相当于客户端

*/

public class Demo01 {

public static void main(String[] args) {

//NO1)创建Jedis对象

//参数一: 连接装Redis数据库的机器的IP

//参数二:Redis数据库占用的端口号

Jedis jedis = new Jedis(“127.0.0.1”,6379);

//NO2)调用Jedis对象的API操作Redis数据库

//选择15号数据库

jedis.select(15);

//将key=value存入15号数据库

jedis.set(“username”,“赵君”);

//取出key=value

System.out.println(jedis.get(“username”));

//NO3关闭Jedis对象

jedis.close();

}

}



package com.itheima.redis;



import java.util.List;

import redis.clients.jedis.Jedis;



/**

* 演示Jedis对象操作Redis内存数据库

* 相当于客户端

*/

public class Demo02 {

public static void main(String[] args) {

//NO1)创建Jedis对象

Jedis jedis = new Jedis(“127.0.0.1”,6379);

//NO2)调用Jedis对象的API操作Redis数据库,默认选择0号数据库

jedis.select(15);

jedis.lpush(“class”,new String[]{“如茶”,“如草”,“如叶”,“如花”});

List<String> list = jedis.lrange(“class”,0,-1);

for(String str : list){

System.out.print(str + ” “);

}

//NO3关闭Jedis对象

jedis.close();

}

}

3.2.3 连接池连接
代码:

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
package com.itheima.redis;


import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;



/**

* 演示Jedis连接池

* 客户端

*/

public class Demo01 {

public static void main(String[] args) {

//NO1)创建Jedis连接池配置对象,类似到c3p0-config.xml文件

JedisPoolConfig config = new JedisPoolConfig();

//NO2)创建Jedis连接池

//设置连接池最多存入10个Jedis对象

config.setMaxTotal(10);

//从连接池中取出Jedis对象最多等2秒

config.setMaxWaitMillis(2000);

//NO3)从Jedis连接池中取出一个Jedis对象

JedisPool pool = new JedisPool(config,“127.0.0.1”,6379);

//NO4)使用Jedis对象操作Redis数据库

Jedis jedis = pool.getResource();

//选择15号数据库

jedis.select(15);

//根据key找value

String username = jedis.get(“username”);

//如果value找到了

if(username != null){

//删除该key

jedis.del(“username”);

}

//NO5)将Jedis对象还回给Jedis连接池

jedis.close();

}

}

3.2.4 编写JedisUtil工具类
代码:

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
package com.itheima.redis.service;


import redis.clients.jedis.Jedis;

import com.itheima.redis.util.JedisUtil;



/**

* 演示通过JedisUtils来获取,操作,关闭Jedis对象

* 客户端

*/

public class Demo01 {

public static void main(String[] args) throws Exception{

//获取Jedis对象

Jedis jedis = JedisUtil.getJedis();

//使用Jedis对象操作Redis数据库

jedis.set(“address”,“长沙”);

//关闭Jedis对象

JedisUtil.close(jedis);

}

}



package com.itheima.redis.util;



import java.util.ResourceBundle;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;



/**

* Jedis工具类

*/

public final class JedisUtil {

private static JedisPool pool;

private static String maxTotal;

private static String maxWaitMillis;

private static String host;

private static String port;

/**

* 读取src/jedis.properties属性文件中的内容

*/

static{

//ResourceBundle专用于去类路径下找*.properties文件,所以扩展名properties可以不写

//建议项目中的配置文件放在src目录下

ResourceBundle rb = ResourceBundle.getBundle(“jedis”);

//根据key找value

maxTotal = rb.getString(“maxTotal”);

maxWaitMillis = rb.getString(“maxWaitMillis”);

host = rb.getString(“host”);

port = rb.getString(“port”);

}

/**

* 创建连接池对象

*/

static{

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxTotal(Integer.parseInt(maxTotal));

config.setMaxWaitMillis(Integer.parseInt(maxWaitMillis));

pool = new JedisPool(config,host,Integer.parseInt(port));

}

private JedisUtil(){

}

/**

* 获取Jedis对象

*/

public static Jedis getJedis() throws Exception{

//如果连接池非空

if(pool != null){

//从连接池中获取Jedis对象

return pool.getResource();

}else{

//return null;

//抛异常

throw new Exception(“Jedis不能为空”);

}

}

/**

* 关闭Jedis对象

*/

public static void close(Jedis jedis) {

if(jedis != null){

jedis.close();

}

}

}



jedis.properties

maxTotal=10

maxWaitMillis=2000

host=127.0.0.1

port=6379

目前为止,我们用过的工具类很多了

04 Redis实战之查询所有省份(重点)

代码:

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
<%@ page language=“java” import=“java.util.*” pageEncoding=“UTF-8”%>

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>

<html>

<head>

<title>My JSP ‘index.jsp’ starting page</title>

<meta http-equiv=“pragma” content=“no-cache”>

<meta http-equiv=“cache-control” content=“no-cache”>

<meta http-equiv=“expires” content=“0”>

<meta http-equiv=“keywords” content=“keyword1,keyword2,keyword3”>

<meta http-equiv=“description” content=“This is my page”>

<!– 引入JQJS文件 –>

<script type=“text/javascript” src=“js/jquery-1.11.3.min.js”></script>

</head>

<body>



<select id=“provinceID”>

<option>选择省份</option>

<%–当浏览器加载index.jsp页面时,动态加载省份–%>

</select>





<script type=“text/javascript”>

//当浏览器加载index.jsp页面时,动态加载省份

$(function(){

//发送AJAX请求

var url = “${pageContext.request.contextPath}/ProvinceServlet”;

var data = null;

var callback = function(backData){//[{“pid”:1,”pname”:”湖南”},{“pid”:2,”pname”:”广东”}]

//用JS语法来解析JSON对象

for(var i=0;i<backData.length;i++){

//获取每个JSON对象的pid

var pid = backData[i].pid;

//获取每个JSON对象的pname

var pname = backData[i].pname;

//创建option标签

var $option = $(“<option value='” + pid + “‘>” + pname + “</option>”);

//将option标签添加到select标签中

$(“#provinceID”).append( $option );

}//for-end

};

var type = “json”;

$.post(url,data,callback,type);

});

</script>



</body>

</html>
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
package com.itheima.redis.web;



import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.itheima.redis.service.ProvinceService;

import com.itheima.redis.util.PrintUtil;



/**

* web层

*/

public class ProvinceServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {

}

public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {

try {

request.setCharacterEncoding(“UTF-8”);

//创建业务层对象,并调用方法

ProvinceService service = new ProvinceService();

String provinceListJSON = service.findAllProvince();

//用IO形式将JSON字符串输出到客户端

PrintUtil.toClient(provinceListJSON,response);

} catch (Exception e) {

e.printStackTrace();

request.setAttribute(“MESSAGE”,“查询所有省份失败”);

request.getRequestDispatcher(“/WEB-INF/message.jsp”).forward(request,response);

}

}

}



package com.itheima.redis.service;



import java.util.List;

import redis.clients.jedis.Jedis;

import com.google.gson.Gson;

import com.itheima.redis.dao.ProvinceDao;

import com.itheima.redis.entity.Province;

import com.itheima.redis.util.JedisUtil;



/**

* service层

*/

public class ProvinceService {

private ProvinceDao dao = new ProvinceDao();

/**

* 查询所有省份

*/

public String findAllProvince() throws Exception{

//获取Jedis对象

Jedis jedis = JedisUtil.getJedis();

//根据key去Redis中找到对应value

String provinceListJSON = jedis.get(“PROVINCE_LIST_JSON”);

//如果key存在

if(provinceListJSON != null){

System.out.println(“去Redis中取”);

//关闭Jedis对象

JedisUtil.close(jedis);

//返回

return provinceListJSON;

//如果key不存在

}else{

System.out.println(“去MySQL中取”);

//调用持久层对象的方法

List<Province> provinceList = dao.findAllProvince();

//为了让以后,少查MySQL,我们将List集合转成JSON字符串

Gson gson = new Gson();

provinceListJSON = gson.toJson(provinceList);

//存入Redis中

jedis.set(“PROVINCE_LIST_JSON”,provinceListJSON);

//关闭Jedis对象

JedisUtil.close(jedis);

//返回

return provinceListJSON;

}

}

}



package com.itheima.redis.dao;



import java.sql.SQLException;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanListHandler;

import com.itheima.redis.entity.Province;

import com.itheima.redis.util.JdbcUtil;



/**

* dao层

*/

public class ProvinceDao {

/**

* 查询所有的省份

*/

public List<Province> findAllProvince() throws SQLException{

//创建QueryRunner对象

QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());

//创建SQL语句

String sql = ” SELECT *” +

” FROM tab_province” +

” ORDER BY pid ASC”;

//创建数组

Object[] params = null;

//执行SQL语句

return runner.query(sql,new BeanListHandler<Province>(Province.class),params);

}

}



package com.itheima.redis.entity;



/**

* 省份

* 与

* tab_province表一一对应

*/

public class Province implements java.io.Serializable{

private int pid;//编号

private String pname;//名字

public Province(){}

public int getPid() {

return pid;

}

public void setPid(int pid) {

this.pid = pid;

}

public String getPname() {

return pname;

}

public void setPname(String pname) {

this.pname = pname;

}

}



package com.itheima.redis.util;



import com.mchange.v2.c3p0.ComboPooledDataSource;



/**

* Jdbc工具类

*/

public final class JdbcUtil {

private JdbcUtil(){}

/**

* 去src/c3p0–config.xml文件

*/

private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

/**

* 获取DataSource

*/

public static ComboPooledDataSource getDataSource() {

return dataSource;

}

}



package com.itheima.redis.util;



import java.util.ResourceBundle;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;



/**

* Jedis工具类

*/

public final class JedisUtil {

private static JedisPool pool;

private static String maxTotal;

private static String maxWaitMillis;

private static String host;

private static String port;

/**

* 读取src/jedis.properties属性文件中的内容

*/

static{

//ResourceBundle专用于去类路径下找*.properties文件,所以扩展名properties可以不写

//建议项目中的配置文件放在src目录下

ResourceBundle rb = ResourceBundle.getBundle(“jedis”);

//根据key找value

maxTotal = rb.getString(“maxTotal”);

maxWaitMillis = rb.getString(“maxWaitMillis”);

host = rb.getString(“host”);

port = rb.getString(“port”);

}

/**

* 创建连接池对象

*/

static{

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxTotal(Integer.parseInt(maxTotal));

config.setMaxWaitMillis(Integer.parseInt(maxWaitMillis));

pool = new JedisPool(config,host,Integer.parseInt(port));

}

private JedisUtil(){

}

/**

* 获取Jedis对象

*/

public static Jedis getJedis() throws Exception{

//如果连接池非空

if(pool != null){

//从连接池中获取Jedis对象

return pool.getResource();

}else{

//return null;

//抛异常

throw new Exception(“Jedis不能为空”);

}

}

/**

* 关闭Jedis对象

*/

public static void close(Jedis jedis) {

if(jedis != null){

jedis.close();

}

}

}



package com.itheima.redis.util;



import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;



/**

* 向客户端输出内容

*/

public final class PrintUtil {

private PrintUtil(){}

public static void toClient(String content,HttpServletResponse response) throws Exception{

response.setContentType(“text/html;charset=UTF-8”);

PrintWriter pw = response.getWriter();

pw.write(content);

pw.flush();

pw.close();

}

}

两种session对象方式的区别

1.getcurrentSession

1.1 获取的对象 无论执行多少次方法,只要是在同一个线程中,获取的是同一个session对象

1.2 对象的关闭 自动关闭session,无需手动关闭

1.3 环境的注册 需要注册session的运行环境

1.4 查询对事物的支持 需要在事务下支持

2.openSession

2.1 获取的对象 每执行一次方法,获取的是新一个session对象

2.2 对象的关闭 手动关闭session对象

2.3 环境的注册 不需要注册session的运行环境

2.4 查询对事物的支持 不需要在事务下支持

ParameterizedType获取java泛型参数类型
前言
这两天在看以前写的ssh项目时,遇到一个问题就是封装的BaseDaoImpl抽象类,构造方法里面是这样写的

1
2
3
4
5
6
Class<T> clazz;

public BaseDaoImpl(){
ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<T>)pt.getActualTypeArguments()[0];
}

当时看到还真不知道里面到底是什么意思,记得以前写时是参考网上写的 ,于是我只有再去网上找答案了,一番搜索终于知道了。

1
2
3
ParameterizedType

getClass().getGenericSuperclass()

返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type,然后将其转换ParameterizedType。
getActualTypeArguments()
返回表示此类型实际类型参数的 Type 对象的数组。[0]就是这个数组中第一个了。简而言之就是获得超类的泛型参数的实际类型。
看意思可能不是很懂,我们直接看例子

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
package com.chen.demo;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class param<T1, T2> {
class A {}
class B extends A {}
private Class<T1> entityClass;
public param (){
Type type = getClass().getGenericSuperclass();
System.out.println(“getClass() == ” + getClass());
System.out.println(“type = ” + type);
Type trueType = ((ParameterizedType)type).getActualTypeArguments()[0];
System.out.println(“trueType1 = ” + trueType);
trueType = ((ParameterizedType)type).getActualTypeArguments()[1];
System.out.println(“trueType2 = ” + trueType);
this.entityClass = (Class<T1>)trueType;
System.out.println(“entityClass = ” + entityClass);
B t = new B();
type = t.getClass().getGenericSuperclass();
System.out.println(“B is A’s super class :” + ((ParameterizedType)type).getActualTypeArguments().length);
}
}
public class ClassDemo extends param<MyClass, MyInvoke>{
public static void main(String[] args) {
ClassDemo classDemo = new ClassDemo();
}
}
package com.chen.demo;
public class MyClass {
}
package com.chen.demo;
public class MyInvoke {
}

我们再看打印结果

1
2
3
4
5
6
getClass() == class com.chen.demo.ClassDemo
type = com.chen.demo.param<com.chen.demo.MyClass, com.chen.demo.MyInvoke>
trueType1 = class com.chen.demo.MyClass
trueType2 = class com.chen.demo.MyInvoke
entityClass = class com.chen.demo.MyInvoke
B is A’s super class :0

从上面结果我们可以总结如下,通过ParameterizedType获取泛型参数Class类型,然后我们就可以通过Class干一系列事情了。。。。。
比如数据库基本CRUD的工具类,直接看工具代码如下:

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
public abstract class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
Class<T> clazz;
public BaseDaoImpl(){
//getClass().getGenericSuperclass()返回表示此 Class
//所表示的实体(类、接口、基本类型或 void)的直接超类的 Type
//然后将其转换ParameterizedType
//getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组
//[0]就是这个数组中第一个了。
ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<T>)pt.getActualTypeArguments()[0];
}
@Override
public void save(T entity) {
getHibernateTemplate().save(entity);
}
@Override
public void delete(Serializable id) {
getHibernateTemplate().delete(findObjectById(id));
}
@Override
public void update(T entity) {
getHibernateTemplate().update(entity);
}
@Override
public T findObjectById(Serializable id) {
return getHibernateTemplate().get(clazz, id);
}
@Override
public List<T> findObjects() {
Query query = (Query) getSession().createQuery(“from ” + clazz.getSimpleName());
return query.list();
}
@Override
public List<T> findObjects(QueryHelper queryHelper){
Query listQuery = getSession().createQuery(queryHelper.getHql());
List<Object> parameters = queryHelper.getParameters();
if(parameters != null){
for(int i = 0; i<parameters.size(); i++){
listQuery.setParameter(i, parameters.get(i));
}
}
return listQuery.list();
}

工具类用到了Spring的orm模块,其次我们最重用的就是可以通过ParameterizedType封装通用的CRUD工具类,在实际的项目中,我们让不同的业务模块继承至该工具类,然后就可以直接使用其CRUD方法了。

hymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎,类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。
与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用。
Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
一:在html页面中引入thymeleaf命名空间,即,此时在html模板文件中动态的属性使用th:命名空间修饰 。

在其它标签使用 th:语法的前提
这样才可以在其他标签里面使用th:
这样的语法.这是下面语法的前提.
二:变量表达式(获取变量值)

获取变量
分析:
1.可以看出获取变量值用$符号,对于javaBean的话使用变量名.属性名方式获取,这点和EL表达式一样2.它通过标签中的th:text属性来填充该标签的一段内容,意思是$表达式只能写在th标签内部,不然不会生效,上面例子就是使用th:text标签的值替换p标签里面的值,至于p里面的原有的值只是为了给前端开发时做展示用的.这样的话很好的做到了前后端分离.意味着p标签中的内容会被表达式#{name}的值所替代,无论模板中它的内容是什么,之所以在模板中“多此一举“地填充它的内容,完全是为了它能够作为原型在浏览器中直接显示出来。
3.访问spring-mvc中model的属性,语法格式为“${}”,如${user.id}可以获取model里的user对象的id属性
4.牛叉的循环<li th:each=”book : ${books}” >
三:URL表达式(引入URL)
1.引用静态资源文件(CSS使用th:href,js使用使用th:src)
比如CSS和JS文件,语法格式为“@{}”,如@{/scripts/jquery-3.1.1.js}会引入/static目录下的/scripts/jquery-3.1.1.js文件

引入URL
2.href链接URL(使用th:href)

引用href的URL
分析:
1)最终解析的href为:
/seconddemo/
/seconddemo/usethymeleaf?name=Dear 相对路径,带一个参数
/seconddemo/usethymeleaf?name=Dear&alis=Dear 相对路径,带多个参数
/seconddemo/usethymeleaf?name=Dear&alis=Dear 相对路径,带多个参数
/seconddemo/usethymeleaf/Dear 相对路径,替换URL一个变量
/seconddemo/usethymeleaf/Dear/Dear 相对路径,替换URL多个变量
2)URL最后的(name=${name})表示将括号内的内容作为URL参数处理,该语法避免使用字符串拼接,大大提高了可读性
3)@{/usethymeleaf}是Context相关的相对路径,在渲染时会自动添加上当前Web应用的Context名字,假设context名字为seconddemo,那么结果应该是/seconddemo/usethymeleaf,即URL中以”/“开头的路径(比如/usethymeleaf将会加上服务器地址和域名和应用cotextpath,形成完整的URL。
4)th:href属性修饰符:它将计算并替换使用href链接URL 值,并放入的href属性中。
5)th:href中可以直接使用静态地址
四:选择或星号表达式
表达式很像变量表达式,不过它们用一个预先选择的对象来代替上下文变量容器(map)来执行
*{customer.name}
被指定的object由th:object属性定义:
<div th:object=”${book}”>
……
<span th:text=”*{title}”>…</span>
……
</div>
分析:
1)如果不考虑上下文的情况下,两者没有区别;星号语法评估在选定对象上表达,而不是整个上下文,什么是选定对象?就是父标签的值。上面的{title}表达式可以理解为${book.title}。(父对象)
2)当然,美元符号和星号语法可以混合使用
小插曲:三和四的变量表达式、URL表达式所对应的属性都可以使用统一的方式:th.attr=“属性名=属性值”的方式来设置,参考第“七.设置属性值”部分
五:文字国际化表达式
文字国际化表达式允许我们从一个外部文件获取区域文字信息(.properties),用Key索引Value,还可以提供一组参数(可选).
#{main.title}
#{message.entrycreated(${entryId})}
可以在模板文件中找到这样的表达式代码:

1
2
3
4
5
6
<table>
……
<th th:text=”#{header.address.city}”>
<th th:text=”#{header.address.country}”>
……
</table>

六:表达式支持的语法
1.字面(Literals)

2.文本操作(Text operations)

3.算术运算(Arithmetic operations)

4.布尔操作(Boolean operations)

5.比较和等价(Comparisons and equality)

6.条件运算符(Conditional operators)

示例一:

1
<h2 th:text=”${expression} ? ‘Hello’ : ‘Something else'”>/h2>

示例二:

1
2
3
4
5
6
7
8
<!– IF CUSTOMER IS ANONYMOUS –>
<div th:if=”${customer.anonymous}”>
<div>Welcome, Gues!</div>
</div>
<!– ELSE –>
<div th:unless=”${customer.anonymous}”>
<div th:text=” ‘Hi,’ + ${customer.name}”>Hi, User</div>
</div>

7.循环
渲染列表数据是一种非常常见的场景,例如现在有n条记录需要渲染成一个表格或li列表标签
该数据集合必须是可以遍历的,使用th:each标签

分析:
循环,在html的标签中,加入th:each=“value:${list}”形式的属性,如可以迭代prods的数据
又如带状态变量的循环:

循环加状态变量

状态变量

默认生成一个名为“变量名Stat”的状态变量
利用状态变量判断:

状态变量判断
七.设置属性值

  1. th:attr 任何属性值,语法格式:th:attr=”属性名=属性值,[属性名=属性值]”
    属性值如果是使用表达式的话:通常有URL表达式@{}和变量表达式${}
    但此标签语法不太优雅
    示例:
1
2
3
4
th:attr=”action=@{/subscribe}”//当然也可以直接使用th:action
th:attr=”src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}” //可直接使用th:src
th:attr=”value=#{subscribe.submit}”//可直接使用th:value
<input type=”checkbox” name=”active” th:attr=”checked=${user.active}”/>

设置多个属性在同一时间 有两个特殊的属性可以这样设置: th:alt-title 和 th:lang-xmllang
th:src=”@{/images/gtvglogo.png}” th:alt-title=”#{logo}”
2.前置和后置添加属性值 th:attrappend 和 th:attrprepend
主要对class和style两个属性
class=”btn” th:attrappend=”class=${‘ ‘ + cssStyle}”
转换后:class=”btn warning”
3.还有两个特定的添加属性 th:classappend 和 th:styleappend
与上面的attrappend功能一样
class=”row” th:classappend=”${prodStat.odd}? ‘odd’”
转换后:奇数行class=”row odd”,偶数行class=”row”
八:内嵌变量Utilities
为了模板更加易用,Thymeleaf还提供了一系列Utility对象(内置于Context中),可以通过#直接访问。
dates : java.util.Date的功能方法类
calendars : 类似#dates,面向java.util.Calendar
numbers : 格式化数字的功能方法类
strings : 字符串对象的功能类,contains,startWiths,prepending/appending等等
objects: 对objects的功能类操作
bools: 对布尔值求值的功能方法
arrays:对数组的功能类方法
lists: 对lists功能类方法
sets
maps
……
代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
${#dates.format(dateVar, ‘dd/MMM/yyyy HH:mm’)}
${#dates.arrayFormat(datesArray, ‘dd/MMM/yyyy HH:mm’)}
${#dates.listFormat(datesList, ‘dd/MMM/yyyy HH:mm’)}
${#dates.setFormat(datesSet, ‘dd/MMM/yyyy HH:mm’)}
${#dates.createNow()}
${#dates.createToday()}
${#strings.isEmpty(name)}
${#strings.arrayIsEmpty(nameArr)}
${#strings.listIsEmpty(nameList)}
${#strings.setIsEmpty(nameSet)}
${#strings.startsWith(name,’Don’)} // also array*, list* and set*
${#strings.endsWith(name,endingFragment)} // also array*, list* and set*
${#strings.length(str)}
${#strings.equals(str)}
${#strings.equalsIgnoreCase(str)}
${#strings.concat(str)}
${#strings.concatReplaceNulls(str)}
${#strings.randomAlphanumeric(count)}//产生随机字符串

八:thymeleaf布局