layout: post
title: 实训项目
date: 2020-12-6
author: XiaoJia849
categories:
- 开发部
tags:
- 后端
- springboot
- 文件处理
项目实训已经度过3周,三周内被迫学会了springboot 和mybatis的基本使用,以下是我的一点总结。以及对文件的操作记录。
- Maven
- Mybatis
- Springboot
- 上传excel与解析
- 上传任意类型文件且保存
- 浏览器下载文件
- java处理word模板
Maven
Maven是个好东西,如果在配置pom.xml时不经常爆红的话。
Maven在我的理解中是一个jar包管理库,使用Maven让我无需导入jar包,如果需要使用这个jar包时,只需要在pom.xml内写入依赖即可,非常方便。
Mybatis
Mybatis内写sql语句调用数据库的资源,把所有涉及与数据库交互的过程全部封装在mapper内的xml文件中,但是对于初次接触MyBatis的我而言不是很友好。当我需要写嵌套查询时,发现此时仅仅是更改sql语句只会引发一串报错,这也就意味着,当sql语句跳出了简简单单的一层插入,更新,查询时,难度大幅度上升了。其实只是我太菜了,要写嵌套查询还是很方便的。
例子
<insert id="createPro">
insert into pro (Pid,Pname,Pcontent,Pnum)
values (#{Pid},#{Pname},#{Pcontent},#{Pnum})
</insert>
<select id="getMaxid" resultType="java.lang.Integer">
select MAX(Pid)
from pro;
</select>
<select id="getPro" resultType="com.demo.model.Pro">
select
Pid,Pname,Pcontent,Pnum,
from pro;
</select>
<update id="setPid">
update stu_team_pro
set Pid=#{pid}
where GroupId=#{groupId};
</update>
和sql里面写嵌套查询没啥区别,我也不知道为什么我在网上搜到的那么复杂ㄟ( ▔, ▔ )ㄏ
总而言之,感谢队友 (_)
<insert id="ReplyGrade">
Update tea_ans
set Grade=#{Grade}
where Tid=#{Tid} and ReplyId in(
select ReplyId
from scen
where GroupId=#{GroupId}
);
</insert>
Springboot
Springboot的亮点在于5层框架,把每层的功能分的十分细致。
- model层描述对象的属性。
- dao层与Mybatis打交道,里面写满各种与数据库相关的方法。
- service层则可以将dao层的方法组合起来使用,当要处理的问题简单时,其实并不需要service层。
- control层用于和前端进行交互,接收数据,调用dao层或者service层的方法进行处理,处理后将结果返回前端。
- config层我只知道可以作为拦截器限制control层与前端的交互。
此外,springboot的优点还在于可以清晰的让每个函数只做一件事,比如说:
函数A要更改数据库,函数B要实现把数据库中的数据拿到前端展示的作用
可是我们要实现的功能是界面上更改数据库传出请求后马上返回到这个页面,要将AB两个函数的功能按顺序使用,那么可以在A函数结束后 return "redirect:/B" ,这样就OK了
之前采用MVC框架写过前后端的代码,那个时候并不知道springboot这么香的存在,哎
上传excel与解析
功能
前端上传excel文件,后端实现获取excel内容,并将对应的内容存入数据库内
要点
- 上传文件的 jsp要进行以下修改
<meta http-equiv="X-UA-Compatible" content="multipart/form-data;charset=utf-8">
<form action="AdminEXC" method="post" enctype="multipart/form-data">
<input type="file" name="exc" accept=".xls,.xlsx" enctype="multipart/form-data" />
<input id="button" type="submit" value="确 定" />
</form>
在jsp的head内和form内都明确上传的数据类型是multipartFile,且限制上传的文件类型为excel
- Maven导包使支持POI且2007之后的excel文件处理
在pom.xml内写入以下内容
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.8</version>
</dependency>
写入以上之后才能使用XSSF
- control层内代码实现
@PostMapping("AdminEXC")
public String export(@RequestParam("exc") MultipartFile file,
HttpServletRequest request, HttpServletResponse response) {
try {
// @RequestParam("file") MultipartFile file 是用来接收前端传递过来的文件
// 1.读取文档file并且把数据流形式存放在inputStream内
InputStream inputStream = file.getInputStream();
//定义工作簿,把数据流以excel文件的形式组织起来,形成工作簿
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);
//定义工作表,工作簿第0页也就是第一张sheet
XSSFSheet xssfSheet;
xssfSheet = xssfWorkbook.getSheetAt(0);
//已知excel第0列内容是专业
//要获取不重复的专业列我采用放入map的方式
Map<String, Integer> map= new HashMap<String,Integer>();
//定义标题行,第0行为标题行,index = 0
XSSFRow titleRow = xssfSheet.getRow(0);
//xssfSheet无法直接获得一列的元素,所以只能用行的for循环
//获取专业列也即map的key 列
for (int rowIndex = 1; rowIndex < xssfSheet.getPhysicalNumberOfRows(); rowIndex++) {
XSSFRow xssfRow = xssfSheet.getRow(rowIndex);
if (xssfRow.getCell(3) == null) {
continue;
}else{
map.put(xssfRow.getCell(3).getStringCellValue(),1);
}
}
//xssfSheet.getPhysicalNumberOfRows()代表这个工作表的行数,并不一定就等于有文字的部分的行数,所以在进行for循环时,判断对应的值是否为null时十分有必要的
//根据key的排列对value进行从上到下的标号
//标号后存入数据库内
int i=0;
//将专业相关信息插入dept表内
for (Map.Entry<String, Integer> entry : map.entrySet()) {
i=i+1;
entry.setValue(i);
//一个数据库插入函数
//把key作为sdept i作为Sdid 插入
proDao.Insdid(i,entry.getKey());
}
//循环取每行的数据,完善学生相关信息
for (int rowIndex = 1; rowIndex < xssfSheet.getPhysicalNumberOfRows(); rowIndex++) {
XSSFRow xssfRow = xssfSheet.getRow(rowIndex);
if (xssfRow.getCell(3) == null) {
continue;
}else{
String sid=xssfRow.getCell(0).getStringCellValue();
String sname=xssfRow.getCell(1).getStringCellValue();
String spwd=sid.substring(0,3)+sid.substring(5,8);
Integer sdid=map.get(xssfRow.getCell(3).getStringCellValue());
proDao.Instu(sid,sname,spwd,sdid);
}
//以上部分为基操,不做描述
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Adminfunc";
}
上传任意类型文件且保存
上传文件的 jsp要进行以下修改
<meta http-equiv="X-UA-Compatible" content="multipart/form-data;charset=utf-8">
<form action="Proupload" method="post" enctype="multipart/form-data">
<select name="pid">
<option value="1">xx</option>
<option value="2">hh</option>
</select>
<input type="file" name="xfile" enctype="multipart/form-data" />
<input id="button" type="submit" value="确 定" />
</form>
在jsp的head内和form内都明确上传的数据类型是multipartFile
@PostMapping("Proupload")
public String Upload(HttpServletRequest request,@RequestParam("xfile") MultipartFile file){
try{
//获取题目id
int pid=Integer.valueOf(request.getParameter("pid"));
//得到文件名
String filename = file.getOriginalFilename();
//得到文件类型
String extFileName = filename.substring(filename.lastIndexOf("." ) +1,filename.length());
//例如上传文件xx.txt
//filename="xx.txt"
//extFileName="txt"
//获取当前所在文件夹的绝对路径realPath
String realpath=request.getSession().getServletContext().getRealPath("/");
//略微修改一下,得到我将把上传的文件夹存入的路径 ——filePath
String filePath=realpath.substring(0,realpath.length()-7)+"resources\\file\\";
String path = filePath + filename;
//以上两者拼接得到一个完整的文件存入的路径
//在这个路径上创建文件
File dest = new File(path);
if (!dest.getParentFile().exists()){
//若此路径不存在则创建目录
dest.getParentFile().mkdir();
}
//将file文件完全复制存入到dest这个文件内
file.transferTo(dest);
//把对应的数据库信息存入
proDao.Inurl(pid,path);
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Teafunc";
}
浏览器下载文件
- jsp内
<form action="download" method="post">
<input type="submit" value="下载">
</form>
- pom.xml内补充依赖
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
</dependency>
- control层
@PostMapping("download")
public static void downFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
//等待被下载的文件的绝对路径
String url="F:\\ne\\AC自动机&TireTree.docx";
//该文件的名字
String filename="AC自动机&TireTree.docx";
//找到该文件
File file=new File(url);
// 文件存在才下载
if (file.exists()) {
OutputStream out = null;
FileInputStream in = null;
try {
// 把文件转化为数据流存储在in内
in = new FileInputStream(file);
// 告诉浏览器下载的方式以及一些设置
// 解决文件名乱码问题,获取浏览器类型,转换对应文件名编码格式,IE要求文件名必须是utf-8, firefo要求是iso-8859-1编码
//获取浏览器信息
String agent = request.getHeader("user-agent");
if (agent.contains("FireFox")) {
//如果是火狐浏览器,则需要转编码
filename = new String(filename.getBytes("UTF-8"), "iso-8859-1");
} else {
//其他的全部设置为UTF-8形式
filename = URLEncoder.encode(filename, "UTF-8");
}
// 设置下载文件的mineType,告诉浏览器下载文件类型
String mineType = request.getServletContext().getMimeType(filename);
//设置相应类型与文件类型一致(因为要下载这个文件)
response.setContentType(mineType);
// 设置一个响应头,无论是否被浏览器解析,都下载
response.setHeader("Content-disposition", "attachment; filename=" + filename);
// 将要下载的文件内容通过输出流写到浏览器
out = response.getOutputStream();
//把输入流的内容全部复制到输出流
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
//复制结束后实现了输出一个一模一样的文件
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
}
}
}
例子
java处理word模板
- jsp内
<meta http-equiv="X-UA-Compatible" content="multipart/form-data;charset=utf-8">
<form action="getGrade" method="post"enctype="multipart/form-data">
<input id="button" type="submit" value="生成成绩"/>
</form>
- pom.xml内
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
- control层
已知我的模板文件在resources/file/下 stugrade.docx
要在同目录下创建文件xx4.docx
@PostMapping("getGrade")
public static String getGrade(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取当前项目的绝对地址
String realpath=request.getSession().getServletContext().getRealPath("/");
String filePath=realpath.substring(0,realpath.length()-7)+"resources\\file\\";
//模板文件地址,下面过程不会更改模板文件
String inputUrl = filePath + "stugrade.docx";
//新生产的文件
String outputUrl=filePath+"xx4.docx";
//在map内按照模板对应位置的英文key补充填写内容value
Map<String,String> map=new HashMap<>();
map.put("Pname","hhh");
map.put("Tname","hhh");
map.put("student","hhh");
map.put("tea1","hhh");
map.put("grade1","hhh");
map.put("tea2","hhh");
map.put("grade2","hhh");
map.put("time","hhh");
map.put("place","hhh");
map.put("grade","hhh");
try {
//获取word文档解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取文章
Iterator<XWPFParagraph> itPara = document.getParagraphsIterator();
while (itPara.hasNext()) {
//获取段落
XWPFParagraph paragraph = (XWPFParagraph) itPara.next();
//获取段落内的最小结构run
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//获取文字
String text = run.getText(0);
if (text != null) {
boolean isSetText = false;
//遍历map寻找key
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
if (text.indexOf(key) != -1) {// 在配置文件中有这个关键字对应的键
isSetText = true;
Object value = entry.getValue();
if (value instanceof String) {
// 文本替换
if (text.contains(key)) {
text = text.replace(key, value.toString());
}
}
}
}
if (isSetText) {
run.setText(text, 0);
}
}
}
}
//创建输出文件
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
//把document的内容写入到stream对应的文件file内
document.write(stream);
stream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Adminfunc";
}
备注
request.getHeader("useradgent")解释
mimetype解释
参考
解析excel
文件上传
解决springMVC文件上传报错: The current request is not a multipart request
从后端下载文件到浏览器
获取本地文件的几种方式
获取项目根目录
试图打开word报错
word替换关键字
poi的jar包参考
XWPF文本替换
参考网址整理时,还有遗漏的,也有些部分是我查看后发现不适用的就没放上来
项目
这个是我们小组6个人的作品,如果允许的话,项目源码将在这个实训结束后上传github网址用于分享 不了,还是算了吧