本文已参与「新人创作礼」活动,一起开启掘金创作之路。
项目上要做一个小的客户端,但是用C#这边做桌面应用程序的不是很熟练,项目要求又比较急,只能用传统的BS架构,java做后台然后前台打包成exe程序。 这里就涉及到一个问题,对于一些数据的存储,列表的增删改查,因为是控制硬件的小插件不想单独设置数据库,需要用文件的形式进行数据的存储,并实现增删改查。
所用到的技术
springboot,swgger,lomock,ConcurrentHashMap,hutool等 swagger是一个在线文档和在线的调试,之前介绍过简单的使用springboot整合swagger-UI和swagger-bootstrap-ui的使用 lomock个工具类库,可以用简单的注解形式来简化代码,提高开发效率。@data get/set方法自动生成 @Log4j/@Slf4j 日志注解等都需要 ConcurrentHashMap它是HashMap的一个线程安全的、支持高效并发的版本 hutool是一个Java工具包,官方网址 提供了大量的“util”包,这里我们用到了FileUtil工具包
准备工作
1.首先我们要准备一个springboot项目
2.idea工具需要set->plugins添加插件
添加之后的目录结构如下
**
正式开始编程,这里我们的思路是首先在文件加载之前就去读取一个json文件,将文件里面的数据放在全局的静态的ConcurrentHashMap 当中,页面查询只是查询ConcurrentHashMap 当进行新增和修改删除操作时,我们只需要对ConcurrentHashMap 进行操作,然后以覆盖的方式将json文件覆盖写入即可。
1.pom文件
**
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.66.Final</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.yml文件
server:
port: 8081
spring:
application:
name: acconfig
control:
file:
controlpath: //controldata.json
timeout: 10
logging:
pattern:
console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(---){faint} %clr(%-40.40logger{39}){cyan}[line:%line] %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39}[line:%line]: %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
level:
com.zkrd: debug
com: error
org: error
io: error
file:
name: ./logs/${spring.application.name}.log
3.启动文件
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Component
public class InitControlData implements ApplicationRunner {
@Autowired
private ControlDataService controlDataService;
@Override
public void run(ApplicationArguments args) throws Exception {
controlDataService.loadDataFromFile();
}
}
这里InitControlData 继承ApplicationRunner ,这样程序在启动的时候就会首先执行这一段代码。
4.实体类
//控制器实体
@Data
public class ControlData {
private String id;
private String name;
private String sex;
private String phone;
private String like;
}
5.swagger配置文件
在这里插入代码片@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("接口文档")
.description("接口文档")
.version("1.0")
.contact(new Contact("刘涛", "", "1299828500@qq.com"))
.build();
}
}
6.Service层
这里我们首先定义全局变量,然后程序启动会调用loadDataFromFile方法,将json文件路径进行解析,如果存在就将文件内容读取到map集合当中去
@Service
public class ControlDataService {
private static ConcurrentHashMap<String, ControlData> controlDataMap = new ConcurrentHashMap<>();
@Value("${control.file.controlpath}")
private String controlFilename;
public void loadDataFromFile() {
ApplicationHome home = new ApplicationHome(getClass());
File jarFile = home.getSource();
String path = jarFile.getParent();
String controlFilePath = path + controlFilename;
if (FileUtil.exist(controlFilePath)) {
String listJson = FileUtil.readString(controlFilePath, "UTF-8");
if (StringUtils.isEmpty(listJson)) return;
List<ControlData> list = JSONUtil.toList(listJson, ControlData.class);
list.forEach(data->{
controlDataMap.put(data.getId(), data);
});
}
}
public List<ControlData> getControlList() {
return new ArrayList(controlDataMap.values());
}
public ControlData getControlDataByid(String id) {
return controlDataMap.get(id);
}
public void saveControlData(ControlData controlData) {
controlDataMap.put(controlData.getId(), controlData);
saveMapToFile();
}
public void removeControlData(String id) {
controlDataMap.remove(id);
saveMapToFile();
}
public void removeAll() {
controlDataMap.clear();
saveMapToFile();
}
private void saveMapToFile() {
ApplicationHome home = new ApplicationHome(getClass());
File jarFile = home.getSource();
String path = jarFile.getParent();
String controlFilePath = path + controlFilename;
FileUtil.writeString(JSONUtil.toJsonStr(getControlList()), controlFilePath, "UTF-8");
}
}
无论是增删改查都是对map集合的操作,用id作为key值,实体类对象作为value,这样对集合的put,remove都能做到增删改的效果。 除了查询之外,设计到map集合的改变,都要调用saveMapToFile将map集合内容重新写入json文件中 FileUtil.writeString第一次调用如果json文件不存在会自动创建
7.Control层增删改查的调用
@RestController
@Slf4j
@RequestMapping(value = "/api/device")
@Api(tags = "列表相关接口")
public class ControlDataController extends JsonController {
@Autowired
private ControlDataService controlDataService;
@PostMapping("list")
@ApiOperation("搜索列表")
public JsonResponse list() {
return okJson(controlDataService.getControlList());
}
@PostMapping("detail")
@ApiOperation("展示详细信息")
public JsonResponse detail(String id) {
return okJson(controlDataService.getControlDataByid(id));
}
@PostMapping("save")
@ApiOperation("保存信息")
public JsonResponse save(HttpServletRequest request
, @RequestBody(required=true)ControlData controlDataInfo) {
if (StringUtils.isAnyEmpty(controlDataInfo.getName(), controlDataInfo.getId())) {
return errorJson("所有参数不能为空,端口不能为0");
}
controlDataService.saveControlData(controlDataInfo);
return okJson();
}
@PostMapping("remove")
@ApiOperation("删除信息")
public JsonResponse remove(String ip) {
controlDataService.removeControlData(ip);
return okJson();
}
@PostMapping("removeAll")
@ApiOperation("清空信息")
public JsonResponse removeAll() {
controlDataService.removeAll();
return okJson();
}
}
**
其他一些文件类
** JsonController
public class JsonController {
protected JsonResponse okJson() {
JsonResponse json = new JsonResponse();
json.setStatus(true);
json.setCode("200");
return json;
}
protected JsonResponse okJson(Object data) {
JsonResponse json = new JsonResponse();
json.setStatus(true);
json.setCode("200");
json.setData(data);
return json;
}
protected JsonResponse okJson(Object data, String message) {
JsonResponse json = new JsonResponse();
json.setStatus(true);
json.setCode("200");
json.setMessage(message);
json.setData(data);
return json;
}
protected JsonResponse errorJson(String message) {
JsonResponse json = new JsonResponse();
json.setStatus(false);
json.setCode("500");
json.setMessage(message);
return json;
}
protected JsonResponse errorJson(String message, Object data) {
JsonResponse json = new JsonResponse();
json.setStatus(false);
json.setCode("500");
json.setMessage(message);
json.setData(data);
return json;
}
}
JsonResponse
@Data
public class JsonResponse {
private String code;
private boolean status;
private String message;
private Object data;
}