我的毕业设计后端技术栈
这篇文章是我写毕设后端遇到的一些问题。
一技术栈
最近在写毕业设计。对于后端的技术栈我是由以下技术完成的。对于毕设内容不作介绍了。说一说遇到的一些问题和如何解决的。
java1.8 springboot2.1.3 maven mysql 5.7 redis 2.18 mybatis tk-mapper jetcache freemaker webSocket git
在编码后使用jenkins 和 阿里云的一台ECS 进行服务器的部署。ECS是ubuntu16.04 在业务中调用了阿里云的短信接口服务进行手机验证码的分发。
虽然编码都是我自己编的。但是我还是把代码放到了我的GitHub私有仓库中了。模拟真实开发场景。下面附一下pom文件。对于一些配置和细节这篇文章就不作细说了。只使用了mybatis的一个生成插件。
对于项目的初始构建具体配置我也写了一个博客。https://blog.csdn.net/finalheart/article/details/89020050
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>zy.healthy</groupId>
<artifactId>healthy-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>healthy-service</name>
<description>this is healthy project</description>
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.37</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!--getter setter-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.4.4</version>
</dependency>
<!--HTTP invoke-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--aliyun sms-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.0.3</version>
</dependency>
<!--添加freeMarker-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--<plugin>
<!–Mybatis-generator插件,用于自动生成Mapper和POJO–>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<!–配置文件的位置–>
<configurationFile>src/main/resources/mybatis-generator-config.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</plugin>-->
</plugins>
</build>
</project>
二Java
在这我使用的是Java1.8 也算是很长时间的一个jdk了。
主要用到的是lambda表达式和stream流。这个在集合的一些过滤分组筛选时有很好的效果。当然我觉得这个东西写的代码比较好看。而对于一些其他的关于Java1.8就没什么使用了。就是该怎么用Java语言就怎么用。没遇到什么问题。
三springboot
至于Java web 编程。我目前学习过的有如下几种吧。
1.servlet+jsp
2.springMvc/struts + jsp + mybatis/hibernate
3.springboot + 其他
我个人比较懒。对于1.2都需要一些配置,而且技术用到的比较旧。我在做的时候就把1.2给拒绝了。选择3.也就是springboot
由于我之前也没怎么写过前端。这时选择的也是springboot这个技术,之前接触到的都是与jsp交互。这次实践也算是一个突破吧。前端我选择的是vue 因为听说比较简单我就尝试了一下。最后毕设也是用这个写的。也还不错。哈哈哈。
对于springboot我之前也有使用过。比较简单。也没遇到什么问题。
下图是我的项目目录结构。(我讨厌8080这个端口)
四.maven
maven我在官网下载的3.6 是比较新的一个版本。我在上文引入了pom文件。这个配置一下maven镜像。在把maven配置到这个项目中就好了。我没有模拟nexus私服的使用。因为觉得没必要吧。等后续我会自己搭着玩。
在这遇到了一个小问题。就是IDEA不是用管理员身份启动的。导致我在terminal中写mvn 命令不好使。用管理员启动idea就好使了。这个也不算困难。
还有一个小问题。就是我run起来的项目编译出的target有问题,导致一些东西没找到。然后我看有东西没找到,就看了一下target中编译好的文件。发现没有。然后我mvn clean package 还是不好使。我就很纳闷。于是我把target直接删了。
在mvn package就好用了。按理说clean 就清理了。但是最后还是用这种暴力的方式解决的。以后也没出现过这个问题。mvn clean package 好用。 至于其他使用maven的问题就没有了。因为我这个项目目录也比较简单。也用不上分布式。
五.MySQL
MySQL我使用的是阿里云服务器上的。
在这我遇到了一个问题。就是乱码问题。我是数据库录入数据时 汉字全是 ??? 然后我就一步一步的排查问题、
整体数据插入环节是客户端发起请求,请求调用dao,链接数据库,执行SQL插入。我就从dao开始尝试。执行一个SQL,然后发现并不好使,就是乱码。所以可以把之前得到环节先略过。然后我检查了一下编辑器的文件编码和数据库连接时jdbc的链接参数、都没问题。然后查数据库的编码。也没问题。最后查数据库服务的编码。也就是mysql server 我发现编码是latin1
然后下一步就是改这个编码为utf-8 改完之后就好用了。至于其他问题暂时还没遇到。
六.redis + jetcache
这个我在这个博客有介绍。https://blog.csdn.net/finalheart/article/details/89020050
用来缓存了一下service查询的结果。这样能快很多。至于其他问题暂时没有遇到。因为使用场景并不多。
七.mybatis+tk-mapper
这个的使用还是出了不少错的。在这个博客也做了介绍。这个博客是我构建项目的博客。https://blog.csdn.net/finalheart/article/details/89020050
八.FreeMaker
我在做的时候把一个数据分析结果用word导出来了。使用的是这个模板引擎。还有一种是使用Apache poi 由于之前用过freemaker在这就用的freemaker 。由于没有博客单独写freemaker 的过程。就在这做出介绍。
以word为例。我先将要导出的word样式调好。在需要导出的数据的地方使用占位符 ${name} 来代替。
然后将文件保存为word xml版本 。然后将拓展名改成ftl 下一步是检查你的ftl 因为会有一些错误产生。你的变量被分开了。你需要做的就是将这个变量变回去。将没用的删掉、然后配置freeMaker。注意下面的代码getter setter 我用了idea的lombok插件。
package zy.healthy.util; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.util.ClassUtils; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URLDecoder; import java.util.*; /** * @Author zhangyong * @Date 2019/5/1 11:01 */ @Getter @Setter @ToString //使用了idea的 lombok插件 @SuppressWarnings("serial") public class OperateWord { private String filePath; //文件路径 private String fileName; //文件名称 private String fileOnlyName; //文件唯一名称 public String createWord(Map<String, Object> dataMap,String reportName,String phone) { //todo 文件的存储路径是本地写死的。放到服务器上会存在异常。 //文件路径 // filePath = ClassUtils.getDefaultClassLoader().getResource("").getPath(); filePath = "E:/tmp/"; //文件唯一名称 fileOnlyName = phone+"_" + reportName + ".doc"; /** 生成word */ WordUtil.createWord(dataMap, "healthy.ftl", filePath, fileOnlyName); return "success"; } /** * 返回最终生成的word文档 文件流 * 下载生成的word文档 */ public InputStream getWordFile() { try { //解决中文乱码 fileName = URLDecoder.decode(fileName, "UTF-8"); /** 返回最终生成的word文件流 */ return new FileInputStream(filePath + File.separator + fileOnlyName); } catch (Exception e) { e.printStackTrace(); return null; } } }
package zy.healthy.util; import freemarker.template.Configuration; import freemarker.template.Template; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.util.Map; /** * @Author zhangyong * @Date 2019/5/1 11:01 */ public class WordUtil { /** * 生成word文件 * @param dataMap word中需要展示的动态数据,用map集合来保存 * @param templateName word模板名称,例如:test.ftl * @param filePath 文件生成的目标路径,例如:D:/wordFile/ * @param fileName 生成的文件名称,例如:test.doc */ public static void createWord(Map dataMap,String templateName,String filePath,String fileName){ try { //创建配置实例 freemarker.template.Configuration; Configuration configuration = new Configuration(); //设置编码 configuration.setDefaultEncoding("UTF-8"); //ftl模板文件 configuration.setClassForTemplateLoading(WordUtil.class,"/"); //获取模板 Template template = configuration.getTemplate(templateName); //输出文件 File outFile = new File(filePath+File.separator+fileName); //如果输出目标文件夹不存在,则创建 if (!outFile.getParentFile().exists()){ outFile.getParentFile().mkdirs(); } //将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8")); //生成文件 template.process(dataMap, out); //关闭流 out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 文件流扔到response中。设置相应的MIME * @param request * @param response * @param inputStream * @param fileName */ public static void download(HttpServletRequest request, HttpServletResponse response, InputStream inputStream, String fileName){ BufferedOutputStream bos = null; try { byte[] buffer = new byte[10240]; String userAgent = request.getHeader("user-agent").toLowerCase(); if (userAgent.contains("msie") || userAgent.contains("like gecko")) { fileName = URLEncoder.encode(fileName, "UTF-8"); } else { fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1"); } response.setCharacterEncoding("utf-8"); // response.setContentType("multipart/form-data"); response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); bos = new BufferedOutputStream(response.getOutputStream()); int bytesRead = 0; while ((bytesRead = inputStream.read(buffer)) != -1) { bos.write(buffer, 0, bytesRead); } } catch (Exception e) { e.printStackTrace(); } finally { if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
*****重点:以上的操作是将文件写入到response的流中。以流的形式返回的,此时你要注意的是你使用的是否是ajax。如果是那么会出现问题。因为ajax不能捕捉流。我查了很久,最后使用的是blob这个对象接收的。下面是前端代码。
this.$http.post('http://127.0.0.1:8088/word', { }, { headers: { }, responseType: 'blob', emulateJSON: true }).then(function (response,request) { // 这里是处理正确的回调 console.log("下载报告 success") console.log(response); const blob = new Blob([response.data]); const fileName = this.formInline.reportName+'.doc'; const elink = document.createElement('a'); elink.download = fileName; elink.style.display = 'none'; elink.href = URL.createObjectURL(blob); document.body.appendChild(elink); elink.click(); URL.revokeObjectURL(elink.href); // 释放URL 对象 document.body.removeChild(elink); }, function (response) { // 这里是处理错误的回调 console.log("下载报告 error") });
九. Git
我自己写也没有冲突。只有一个master分支,也不用合并。所有没遇到什么错误。关于git 本地保存密码这个是一个问题。
我总结在了这个博客:https://blog.csdn.net/finalheart/article/details/89048883
十.Jenkins
在实习时学到了这个Jenkins的这个东西。发现是个好东西。所有我私下也自己搭建了一下
我总结在了这篇博客:https://blog.csdn.net/finalheart/article/details/89046101
十一. webSocket
这个功能还没加。打算单独写一篇博客总结。暂未开通。
解决MySQL博客参考:https://blog.csdn.net/jzd1997/article/details/77533026
解决ajax处理流博客参考:https://blog.csdn.net/zqqyaa/article/details/85617232
解决freemaker 参考博客:https://download.csdn.net/download/zhaobaoqiang88888/9803524