tonglin0325的个人主页

SpringBoot学习笔记——统一的异常处理

可以使用 @RestControllerAdvice 拦截异常并进行统一处理

1.首先定义统一的异常码 ResultCode,

其中code以HTTP code status为前缀,后缀为具体异常编号

message为异常消息,前端可以直接拿来显示给用户

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
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ResultCode {

// 200
SUCCESS(200, "成功"),

// 401
UN_AUTH(40101, "该用户未认证"),

// 403
ACCESS_DENIED(40301, "该用户无权限"),

// 404
API_NOT_FOUND(40401, "请求的API不存在"),
RESOURCE_NOT_FOUND(40402, "请求的资源不存在"),

// 500
SYS_UNKNOWN_ERROR(50001, "未知系统错误,请稍后再试"),

// 状态码
private Integer code;
// 提示信息
private String message;

}

  1. 定义全局的异常处理

比如在其中对API接口不存在抛出的异常 NoHandlerFoundException 进行了拦截,并返回统一的异常码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import com.example.demo.common.ControllerResponseT;
import com.example.demo.common.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(NoHandlerFoundException.class)
public ControllerResponseT apiNotFoundException(final Throwable e, final HttpServletRequest request) {
String message = ResultCode.API_NOT_FOUND.getMessage();
log.error(message + " => {}", e.getMessage());
return ControllerResponseT.ofFail(ResultCode.API_NOT_FOUND.getCode(), message, " API [" + request.getRequestURI() + "] 不存在");
}

}

其中对于404的异常捕获不到的话,需要在application.properties中添加配置来解决

1
2
3
4
# mvc
spring.mvc.throw-exception-if-no-handler-found=true
spring.mvc.static-path-pattern=/resources/**

全文 >>

SpringBoot学习笔记——缓存

Springboot可以使用Ehcache或者redis作为缓存

1.Ehcache缓存

参考:SpringBoot学习-(十八)SpringBoot整合EhCache

添加依赖,starter+ehcache

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

添加配置文件 ecache.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

<!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
<!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
<!-- 缓存配置
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk
store persists between restarts of the Virtual Machine. The default value
is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是
LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。 -->

<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>
<!-- 默认缓存 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">

<persistence strategy="localTempSwap"/>
</defaultCache>

<!-- 测试 -->
<cache name="GoodsType"
eternal="false"
timeToIdleSeconds="2400"
timeToLiveSeconds="2400"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU">
</cache>

</ehcache>

添加 @EnableCaching注解 开启缓存

 

 

2.Redis缓存

 

全文 >>

Flink学习笔记——Flink MySQL CDC

Flink CDC提供了一系列connector,用于从其他数据源获取变更数据(change data capture),其中的Flink MySQL CDC基于Debezium

官方文档

1
2
https://ververica.github.io/flink-cdc-connectors/release-2.3/content/about.html

官方github

1
2
https://github.com/ververica/flink-cdc-connectors

Flink和Flink CDC的版本对应关系参考:

1
2
https://nightlies.apache.org/flink/flink-cdc-docs-release-3.1/docs/connectors/flink-sources/overview/

各种数据源使用案例,参考:

基于 AWS S3、EMR Flink、Presto 和 Hudi 的实时数据湖仓 – 使用 EMR 迁移 CDH

Flink CDC关于source和sink全调研及实践

全文 >>

SpringBoot学习笔记——mock

可以使用mock对springboot web接口进行测试

1.依赖

1
2
3
4
5
6
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

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
import org.apache.tomcat.util.codec.binary.Base64;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import javax.annotation.Resource;

import java.nio.charset.StandardCharsets;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

@Resource
private MockMvc mockMvc;

@Test
public void helloTest() throws Exception {
String expect = "{\"code\":200,\"msg\":\"hello: 1\",\"data\": null}";
String auth = "admin:admin";
byte[] originAuth = auth.getBytes(StandardCharsets.US_ASCII);
byte[] encodedAuth = Base64.encodeBase64(originAuth);
String authHeader = "Basic " + new String(encodedAuth);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", authHeader);
mockMvc.perform(MockMvcRequestBuilders.get("/hello/1")
.headers(headers))
.andExpect(MockMvcResultMatchers.content().json(expect))
.andDo(MockMvcResultHandlers.print());
}

}

测试GET请求

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
MockHttpServletRequest:
HTTP Method = GET
Request URI = /hello/1
Parameters = {}
Headers = [Authorization:"Basic YWRtaW46YWRtaW4="]
Body = null
Session Attrs = {SPRING_SECURITY_CONTEXT=SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=admin, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=1], Granted Authorities=[ROLE_USER]]]}

Handler:
Type = com.example.demo.controller.HelloController
Method = com.example.demo.controller.HelloController#hello(Integer)

Async:
Async started = false
Async result = null

Resolved Exception:
Type = null

ModelAndView:
View name = null
View = null
Model = null

FlashMap:
Attributes = null

MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = application/json
Body = {"code":200,"msg":"hello: 1","data":null}
Forwarded URL = null
Redirected URL = null
Cookies = []

Process finished with exit code 0

测试POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
@Transactional
public void createUserTest() throws Exception {
String expect = "{\"code\":200,\"msg\":\"success\",\"data\": null}";
String auth = "admin:admin";
byte[] originAuth = auth.getBytes(StandardCharsets.US_ASCII);
byte[] encodedAuth = Base64.encodeBase64(originAuth);
String authHeader = "Basic " + new String(encodedAuth);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", authHeader);
mockMvc.perform(
MockMvcRequestBuilders.post("/user")
.headers(headers)
.contentType(MediaType.APPLICATION_JSON)
.content("{\n" +
" \"username\": \"admin\",\n" +
" \"password\": \"admin\"\n" +
"}"))
.andExpect(MockMvcResultMatchers.content().json(expect))
.andDo(MockMvcResultHandlers.print());
}  

在对POST请求的测试中,添加了 @Transactional 注解,用于在对测试中插入的数据进行回滚,避免插入脏数据

全文 >>

SpringBoot学习笔记——统一的接口response格式

对于接口的返回结果,需要有统一的结构,因为对于不用考虑流量费用的内部系统,对接口数据长度往往不太介意

开源项目的接口规范案例:

1.阿里云:

阿里云健康码引擎的response结构 ResponseResult

ResponseResult代码 参考:

1
2
https://github.com/aliyun/alibabacloud-whiteboard-callbackservice-demo/blob/master/src/main/java/com/aliyun/rtc/whiteboard/models/ResponseResult.java

返回体结构

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
/**
* 自动生成的请求ID,建议回传互动白板服务,以便日志跟踪
*/
private String requestId;

/**
* 响应状态
*/
private boolean responseSuccess;

/**
* 响应成功结果体
*/
private T result;

/**
* 响应失败错误信息
*/
private String errorCode;
private String errorMsg;

/**
* 成功响应
*/
public static <T> ResponseResult<T> getSuccessResult(String requestId, T v) {
ResponseResult<T> result = new ResponseResult<>();
result.setRequestId(requestId);
result.setResponseSuccess(true);
result.setResult(v);
return result;
}

/**
* 错误响应
*/
public static <T> ResponseResult<T> getErrorResult(String requestId, String errorCode, String errorMsg) {
ResponseResult<T> result = new ResponseResult<>();
result.setRequestId(requestId);
result.setResponseSuccess(false);
result.setErrorCode(errorCode);
result.setErrorMsg(errorMsg);
return result;
}

线上阿里云的dataworks的某接口API的response字段:

data是返回的数据,errCode是错误码,errMsg是错误信息,requestId是请求的uuid

全文 >>

Java——下拉列表框,复选框,列表框,文件选择框


 

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
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;

class MyComboBox{
private JFrame frame = new JFrame("窗体"); //定义窗体
private Container cont = frame.getContentPane(); //得到窗体容器
private JComboBox jcb1 = null; //定义下拉列表框
private JComboBox jcb2 = null; //定义下拉列表框
public MyComboBox(){
this.frame.setLayout(new GridLayout(2,2));
String nations[] = {"中国","美国","韩国","法国","英国"};
Vector<String> v = new Vector<String>(); //定义一个Vector集合
v.add("元素1");
v.add("元素2");
v.add("元素3");
this.jcb1 = new JComboBox(nations);
this.jcb2 = new JComboBox(v);
//定义一个列表框的边框显示条
jcb1.setBorder(BorderFactory.createTitledBorder("哪个国家?"));
jcb2.setBorder(BorderFactory.createTitledBorder("Vector?"));
jcb1.setMaximumRowCount(3); //最多显示3个选项
jcb2.setMaximumRowCount(3);
cont.add(this.jcb1);
cont.add(this.jcb2);
cont.add(new JLabel("下拉列表框"));
this.frame.setSize(330,200);
this.frame.setVisible(true);
this.frame.addWindowListener(new WindowAdapter(){ //加入事件监听
public void windowClosing(WindowEvent arg0) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
System.exit(1);
}
});
}
}


//主类
//Function : MyComboBox_demo
public class MyComboBox_demo {

public static void main(String[] args) {
// TODO 自动生成的方法存根
new MyComboBox();
}

}

 

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
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;

import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;

class MyComboBoxModel extends AbstractListModel implements ComboBoxModel{

String nations[] = {"中国","美国","韩国","法国","英国"};
String item = null;

@Override
public int getSize() {
// TODO 自动生成的方法存根
return this.nations.length;
}

@Override
public Object getElementAt(int index) {
// TODO 自动生成的方法存根
return this.nations[index];
}

@Override
public void setSelectedItem(Object anItem) {
// TODO 自动生成的方法存根
this.item = (String) anItem;
}

@Override
public Object getSelectedItem() {
// TODO 自动生成的方法存根
return this.item;
}

}

class MyComboBox{
private JFrame frame = new JFrame("窗体"); //定义窗体
private Container cont = frame.getContentPane(); //得到窗体容器
private JComboBox jcb1 = null; //定义下拉列表框
private JComboBox jcb2 = null; //定义下拉列表框
public MyComboBox(){
this.frame.setLayout(new GridLayout(2,2));
// String nations[] = {"中国","美国","韩国","法国","英国"};
// Vector<String> v = new Vector<String>(); //定义一个Vector集合
// v.add("元素1");
// v.add("元素2");
// v.add("元素3");
// this.jcb1 = new JComboBox(nations);
// this.jcb2 = new JComboBox(v);
this.jcb1 = new JComboBox(new MyComboBoxModel()); //实例化JComboBox
//定义一个列表框的边框显示条
jcb1.setBorder(BorderFactory.createTitledBorder("哪个国家?"));
// jcb2.setBorder(BorderFactory.createTitledBorder("Vector?"));
jcb1.setMaximumRowCount(3); //最多显示3个选项
// jcb2.setMaximumRowCount(3);
cont.add(this.jcb1);
// cont.add(this.jcb2);
cont.add(new JLabel("下拉列表框"));
this.frame.setSize(330,200);
this.frame.setVisible(true);
this.frame.addWindowListener(new WindowAdapter(){ //加入事件监听
public void windowClosing(WindowEvent arg0) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
System.exit(1);
}
});
}
}

public class MyComboBox_demo {

public static void main(String[] args) {
// TODO 自动生成的方法存根
new MyComboBox();
}

}

 

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
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;

import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;

class MyComboBox implements ItemListener,ActionListener{
private JFrame frame = new JFrame("窗体"); //定义窗体
private Container cont = frame.getContentPane(); //得到窗体容器
private JComboBox jcb1 = null; //定义下拉列表框
private JLabel label = new JLabel("标签"); //定义标签
private String fontSize[] = {"10","11","12"};

public MyComboBox(){
this.frame.setLayout(new GridLayout(2,2));

this.jcb1 = new JComboBox(this.fontSize); //实例化JComboBox
//定义一个列表框的边框显示条
jcb1.setBorder(BorderFactory.createTitledBorder("请选择显示文字大小"));

jcb1.addItemListener(this); //加入选项监听
jcb1.addActionListener(this); //加入动作监听

jcb1.setMaximumRowCount(3); //最多显示3个选项
jcb1.setEditable(true); //设置可编辑文本
jcb1.configureEditor(jcb1.getEditor(), "12"); //定义默认值
this.changeFontSize(12); //设置默认字体

cont.add(this.jcb1);
cont.add(label);

cont.add(new JLabel("下拉列表框"));
this.frame.setSize(330,200);
this.frame.setVisible(true);
this.frame.addWindowListener(new WindowAdapter(){ //加入事件监听
public void windowClosing(WindowEvent arg0) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
System.exit(1);
}
});
}
@Override
public void actionPerformed(ActionEvent e) { //输入信息时触发
// TODO 自动生成的方法存根
String itemSize = (String) this.jcb1.getSelectedItem(); //得到选项
int Size = 12;
try{
Size = Integer.parseInt(itemSize); //字符串转整数
}catch(Exception ex){
this.jcb1.getEditor().setItem("输入的不是数字");
}
this.changeFontSize(Size);
if(!this.isExists(itemSize)){
this.jcb1.addItem(jcb1.getSelectedItem()); //不存在,加入下拉选项
}
}
@Override
public void itemStateChanged(ItemEvent e) {
// TODO 自动生成的方法存根

}

public void changeFontSize(int size){ //改变文字大小
Font font = new Font("Serief",Font.BOLD,size); //定义Font对象
this.label.setFont(font); //设置文字大小
}

public boolean isExists(String item){
boolean flag = false;
for(int i =0;i<this.jcb1.getItemCount();i++){
if(item.equals(this.jcb1.getItemAt(i))){
flag = true;
}
}
return flag;
}

}

public class MyComboBox_demo {

public static void main(String[] args) {
// TODO 自动生成的方法存根
new MyComboBox();
}

}

 

全文 >>

Java——Swing事件处理

 

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
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

class MyWindowEventHandle implements WindowListener{ //实现窗口监听

@Override
public void windowOpened(WindowEvent e) { //窗口打开时触发
// TODO 自动生成的方法存根
System.out.println("windowOpened-->窗口被打开");
}

@Override
public void windowClosing(WindowEvent e) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
}

@Override
public void windowClosed(WindowEvent e) { //窗口被关闭时触发
// TODO 自动生成的方法存根
System.out.println("windowClosed-->窗口被关闭");
}

@Override
public void windowIconified(WindowEvent e) { //窗口最小化时触发
// TODO 自动生成的方法存根
System.out.println("windowIconified-->窗口最小化");
}

@Override
public void windowDeiconified(WindowEvent e) { //窗口从最小化恢复
// TODO 自动生成的方法存根
System.out.println("windowDeiconified-->窗口从最小化恢复");
}

@Override
public void windowActivated(WindowEvent e) { //设置为非活动窗口是触发
// TODO 自动生成的方法存根
System.out.println("windowActivated-->窗口被选中");
}

@Override
public void windowDeactivated(WindowEvent e) { //设置为活动窗口是触发
// TODO 自动生成的方法存根
System.out.println("windowDeactivated-->取消窗口选中");
}

}

public class MyWindowListener_demo {

public static void main(String[] args) {
// TODO 自动生成的方法存根
JFrame f = new JFrame("Swing窗口"); //实例化窗体对象
f.addWindowListener(new MyWindowEventHandle());
f.setSize(440, 320); //设置窗体
f.setLocation(300,200); //设置显示位置
f.setVisible(true);
}

}

 

 

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
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

class myWindowEventHandle extends WindowAdapter{
//此时可以根据自己的需要覆写方法
public void windowClosing(WindowEvent e) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
System.exit(1);
}
}

public class WindowAdapter {

public static void main(String[] args) {
// TODO 自动生成的方法存根
JFrame f = new JFrame("Swing窗口"); //实例化窗体对象
f.addWindowListener(new myWindowEventHandle());
// f.addWindowListener(new WindowAdapter(){
//
// public void windowClosing(WindowEvent e) { //窗口关闭时触发,按下关闭按钮
// // TODO 自动生成的方法存根
// System.out.println("windowClosing-->窗口关闭");
// System.exit(1);
// }
// });

f.setSize(440, 320); //设置窗体
f.setLocation(300,200); //设置显示位置
f.setVisible(true);
}

}

 

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
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

class ActionHandle{
private JFrame frame = new JFrame("窗口"); //定义一个窗口对象
private JButton but = new JButton("显示按钮"); //定义一个按钮
private JLabel lab = new JLabel(); //定义一个标签
private JTextField jtf = new JTextField(10); //定义一个文本域
private JPanel pan = new JPanel();
public ActionHandle(){
Font font = new Font("Serief",Font.ITALIC+Font.BOLD,28);
lab.setFont(font);
lab.setText("设置显示的文字");
but.addActionListener(new ActionListener(){ //采用匿名内部类
public void actionPerformed(ActionEvent arg0){
if(arg0.getSource() == but){ //判断触发源是否是标签
lab.setText(jtf.getText()); //将文本文字设置到标签
}
}
});

frame.addWindowListener(new WindowAdapter(){ //加入动作监听
public void windowClosing(WindowEvent e) { //窗口关闭时触发,按下关闭按钮
// TODO 自动生成的方法存根
System.out.println("windowClosing-->窗口关闭");
System.exit(1);
}
});
frame.setLayout(new GridLayout(2,1)); //定义窗体布局,2行1列
pan.setLayout(new GridLayout(1,2)); //定义窗体布局,1行2列
pan.add(jtf);
pan.add(but);
frame.add(pan);
frame.add(lab);
frame.pack();
frame.setVisible(true);
}
}

public class ActionListener_demo {

public static void main(String[] args) {
// TODO 自动生成的方法存根
new ActionHandle();
}

}

全文 >>

SpringBoot学习笔记——aop

它是一种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想。用于切入到指定类指定方法的代码片段叫做切面,而切入到哪些类中的哪些方法叫做切入点

AOP编程允许把遍布应用各处的功能分离出来形成可重用的组件

 

实现一个AOP可以分成下面几个步骤:

1.引入依赖 

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.自定义注解 @Permission,其中的 @Target 和 @Retention 元注解参考:元注解(Annotation)

1
2
3
4
5
6
7
8
9
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
}

参考

全文 >>

SpringBoot学习笔记——统一的service接口

统一的service接口基于统一的mapper,参考:Mybatis学习笔记——通用mapper

接口AbstractService

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
package com.example.demo.core.service;

import java.util.List;

public interface AbstractService<T> {

/**
* 获取所有
*
* @return List<T>
*/
List<T> listObjects();

/**
* 通过key查找
*
* @param key Object
* @return T
*/
T selectByKey(Object key);

/**
* 根据实体条件查找
*
* @param example Object
* @return List<T>
*/
List<T> selectByExample(Object example);

/**
* 持久化
*
* @param entity T
* @return key
*/
int save(T entity);

/**
* 通过主鍵刪除
*
* @param key Object
*/
int deleteByKey(Object key);

/**
* 通过example条件刪除
*
* @param example T
*/
int deleteByExample(T example);

/**
* 更新
*
* @param entity T
*/
int update(T entity);

}

抽象类AbstractServiceImpl

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
package com.example.demo.core.service.impl;

import com.example.demo.core.mapper.MyMapper;
import com.example.demo.core.service.AbstractService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public abstract class AbstractServiceImpl<T> implements AbstractService<T> {

@Autowired
protected MyMapper<T> mapper;

@Override
public List<T> listObjects() {
return mapper.selectAll();
}

@Override
public T selectByKey(Object key) {
return mapper.selectByPrimaryKey(key);
}

@Override
public List<T> selectByExample(Object example) {
return mapper.selectByExample(example);
}

@Override
@Transactional
public int save(T entity) {
return mapper.insert(entity);
}

@Override
@Transactional
public int deleteByKey(Object key) {
return mapper.deleteByPrimaryKey(key);
}

@Override
@Transactional
public int deleteByExample(Object key) {
return mapper.deleteByExample(key);
}

@Override
@Transactional
public int update(T entity) {
return mapper.updateByPrimaryKeySelective(entity);
}

}

参考:

1
2
https://github.com/febsteam/FEBS-Security/blob/master/febs-common/src/main/java/cc/mrbird/common/service/impl/BaseService.java

以及

1
2
https://github.com/Zoctan/WYUOnlineJudge/blob/master/api/src/main/java/com/zoctan/api/core/service/AbstractService.java

之后在使用的时候,可以通过继承AbstractServiceImpl的方式,来省略一些通用service方法的编写,比如

全文 >>