1 ssm整合PageHelper
1.1 导入jar包
jsqlparser-3.1.jar
pagehelper-5.1.10.jar
1.2 配置pagehelper插件
- 方式1:如果有mybatis的配置文件:在mybatis的配置文件中添加
<!-- 导入pagehelper的插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
- 方式2:如果没有mybatis的配置文件:在spring的核心配置文件中添加
<!--3.创建sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--配置mybatis 插件-->
<property name="plugins">
<set>
<!--配置pageHelper 分页插件-->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!--方言:-->
<prop key="helperDialect">mysql</prop>
</props>
</property>
</bean>
</set>
</property>
</bean>
1.3 创建dao
<select id="getAll" resultType="com.zhiyou100.entity.Student">
select * from student
</select>
<select id="getAllByMinScore" resultType="com.zhiyou100.entity.Student" parameterType="float">
select * from student where score > #{score}
</select>
<!-- int count();-->
<select id="count" resultType="int">
select count(*) from student
</select>
<select id="countByMinScore" resultType="int" parameterType="float">
select count(*) from student where score > #{score}
</select>
1.4 创建service
public PageInfo<Student> getAllFenYe(int pageNumber) {
int pageSize=5;
PageHelper.startPage(pageNumber, pageSize);
PageInfo<Student> info=new PageInfo<>(studentMapper.getAll());
//通过构造方法传递一个list 其他属性都有值
//不能通过set方法传递:否则只有当前属性有值
//info.setList(studentMapper.getAll());
//info.setTotal(studentMapper.count());//设置总记录数
//info.setPages((int)Math.ceil(studentMapper.count()*1.0/pageSize));
//info.setPageNum(pageNumber);
return info;
}
public PageInfo<Student> getAllByMinScoreFenYe(int pageNumber,float score) {
int pageSize=5;
PageHelper.startPage(pageNumber, pageSize);
PageInfo<Student> info=new PageInfo<>();
info.setList(studentMapper.getAllByMinScore(score));
info.setTotal(studentMapper.countByMinScore(score));//设置总记录数
info.setPages((int)Math.ceil(studentMapper.countByMinScore(score)*1.0/pageSize));
info.setPageNum(pageNumber);
return info;
}
1.5 test测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring_config.xml","classpath:springmvc_config.xml"})
public class TestStudentService {
@Autowired//引入要测试的类
private StudentService studentService;
@Test//单元测试要求:类必须是public:方法声明必须是 public void xx();
public void testGetAll(){
System.out.println(studentService.getAllFenYe(2));
}
@Test//单元测试要求:类必须是public:方法声明必须是 public void xx();
public void testGetAllByMinScore(){
System.out.println(studentService.getAllByMinScoreFenYe(2, 20));
}
}
1.6 action
@RequestMapping("/getAllFenYe.action")
public String getAllFenYeMethod(@RequestParam(value="pageNumber",required=false,defaultValue="1")int pageNumber,Model m){
PageInfo<Student> pageInfo=studentService.getAllFenYe(pageNumber);
m.addAttribute("pageInfo", pageInfo);
return "student_manager02";
}
1.7 jsp:student_manager02.jsp
<script type="text/javascript" src="<c:url value='/js/jquery-1.6.4.min.js'/>"></script>
<h1>学生管理页面2:分页</h1>
<c:if test="${empty requestScope.pageInfo}">
<jsp:forward page="/student/getAllFenYe.action?pageNumber=1"/>
</c:if>
<c:if test="${not empty requestScope.message}">
提示信息是:${requestScope.message}
</c:if>
<table>
<tr>
<th>顺序</th>
<th>学号</th>
<th>名字</th>
<th>年龄</th>
<th>党员</th>
<th>生日</th>
<th>分数</th>
<th>真名</th>
</tr>
<c:forEach items="${requestScope.pageInfo.list}" varStatus="vs" var="stu">
<tr>
<td>${vs.index+1}</td>
<td>${stu.sid}</td>
<td>${stu.sname}</td>
<td>${stu.sage}</td>
<td>
<c:choose>
<c:when test="${stu.sdy}"> 是</c:when>
<c:otherwise>否</c:otherwise>
</c:choose>
</td>
<td>
<fmt:formatDate value="${stu.sbirthday}" pattern="yyyy年MM月dd日"/>
</td>
<td>${stu.score}</td>
<td>${stu.realName}</td>
</tr>
</c:forEach>
</table>
requestScope.pageInfo.pages=${requestScope.pageInfo.pages}<br/>
<div id="div_fenye">
<c:if test="${requestScope.pageInfo.pageNum != 1}">
<a href="<c:url value='/student/getAllFenYe.action?pageNumber=${requestScope.pageInfo.pageNum-1}'/>">上一页</a>
</c:if>
<c:forEach begin="1" end="${requestScope.pageInfo.pages}" var="pn">
<c:choose>
<c:when test="${pn eq requestScope.pageInfo.pageNum}">
[ ${pn} ]
</c:when>
<c:otherwise>
<a href="<c:url value='/student/getAllFenYe.action?pageNumber=${pn}'/>"> ${pn} </a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${requestScope.pageInfo.pageNum lt requestScope.pageInfo.pages}">
<a href="<c:url value='/student/getAllFenYe.action?pageNumber=${requestScope.pageInfo.pageNum+1}'/>">下一页</a>
</c:if>
</div>
1.8 效果
2 poi
2.1 概念
Apache POI [1] 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
2.2 下载jar包
https://www.apache.org/dyn/closer.lua/poi/release/bin/poi-bin-4.0.0-20180907.tar.gz
2.3 类解析
HSSF [1] - 提供读写Microsoft Excel XLS格式档案的功能。
XSSF [1] - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
HWPF [1] - 提供读写Microsoft Word DOC格式档案的功能。
HSLF [1] - 提供读写Microsoft PowerPoint格式档案的功能。
HDGF [1] - 提供读Microsoft Visio格式档案的功能。
HPBF [1] - 提供读Microsoft Publisher格式档案的功能。
HSMF [1] - 提供读Microsoft Outlook格式档案的功能。
2.4 创建方法:写excel
public static void createExcel()throws Exception{
String[] rowHeads={"sid","sname","sage","sdy","sbirthday","score","realName"};
//1 创建工作薄
HSSFWorkbook book=new HSSFWorkbook();
//2 创建一个sheet表格对象
HSSFSheet sheet=book.createSheet("Student");
//3 创建第一列:列标题
HSSFRow row1=sheet.createRow(0);
//4 创建标题的单元格
for (int i = 0; i < rowHeads.length; i++) {
HSSFCell celli=row1.createCell(i);
celli.setCellValue(rowHeads[i]);
}
//5 创建列 写入数据
List<Student> list=new ArrayList<Student>();
for (int i = 0; i <10; i++) {
list.add(new Student(
(int)(Math.random()*1000+2000),
UUID.randomUUID().toString().substring(1, 5),
(int)(Math.random()*10+15),
Math.random()>0.5,
new Date(2020-1900, (int)(Math.random()*12+1), (int)(Math.random()*30+1)),
(int)(Math.random()*1000)/10.0f,
"无名氏"+i,
null, null));
}
for (int j = 0; j < list.size(); j++) {
HSSFRow rowj=sheet.createRow(j+1);
Student stu=list.get(j);
rowj.createCell(0).setCellValue(stu.getSid());
rowj.createCell(1).setCellValue(stu.getSname());
rowj.createCell(2).setCellValue(stu.getSage());
rowj.createCell(3).setCellValue(stu.getSdy());
//创建一个日期格式cellstyle
CellStyle dateStyle=book.createCellStyle();
dateStyle.setDataFormat(book.createDataFormat().getFormat("yyyy-MM-dd"));
HSSFCell cell4=rowj.createCell(4);
cell4.setCellStyle(dateStyle);
cell4.setCellValue(stu.getSbirthday());
rowj.createCell(5).setCellValue(stu.getScore());
rowj.createCell(6).setCellValue(stu.getRealName());
}
//6 把book写道目的文件中
book.write(new File("e:\\poi\\student_1.xls"));
book.close();
}
2.5 创建方法:读excel:把excel中数据每行读成一个对象
- 规则1:表格名必须是类名
- 规则2:列标题必须是属性名
//读取excel文件
public static List<Object> readExcel(File file,String className)throws Exception{
//1 创建工作薄:读取源文件
HSSFWorkbook book=new HSSFWorkbook(new FileInputStream(file));
//2 获取第一个表格
HSSFSheet sheet=book.getSheet(className);
//3 获取第一行:列标题 对应的时类的属性名
HSSFRow row1=sheet.getRow(0);
//创建一个数组存储属性名
List<String> fieldNames=new ArrayList<>();
Iterator<Cell> it=row1.cellIterator();
while(it.hasNext()){
Cell cell=it.next();
fieldNames.add(cell.getStringCellValue());//存储列明:属性名
}
//遍历其他行
List<Object> listObj=new ArrayList<>();
Class cla=Class.forName("com.zhiyou100.entity."+className);
for (int i = 1; i < sheet.getLastRowNum(); i++) {
HSSFRow rowi=sheet.getRow(i);
//每行对应一个className类型的对象
Object obj=cla.newInstance();
for (int j = 0; j <rowi.getLastCellNum(); j++) {
Object fieldValue;
HSSFCell cellij=rowi.getCell(j);
//获取其值
//System.out.println(cellij.getCellStyle()+":"+cellij.getCellType()+":::"+j);
if(cellij.getCellType()==CellType.BOOLEAN){
fieldValue=cellij.getBooleanCellValue();
}else if(cellij.getCellType()==CellType.NUMERIC){
fieldValue=cellij.getNumericCellValue();
}else{
fieldValue=cellij.getStringCellValue();
}
//把值赋值给obj的属性
Field fieldj=cla.getDeclaredField(fieldNames.get(j));
fieldj.setAccessible(true);
fieldValue=changeValue(fieldj,fieldValue);//
fieldj.set(obj, fieldValue);
}
listObj.add(obj);
}
book.close();
return listObj;
}
//把value转换为field对应的类型:
private static Object changeValue(Field field,Object value){
Class type=field.getType();
if(type==int.class||type==Integer.class){
return (int)((double)value);
}
if(type==short.class||type==Short.class){
return (short)((double)value);
}
if(type==byte.class||type==Byte.class){
return (byte)((double)value);
}
if(type==long.class||type==Long.class){
return (long)((double)value);
}
if(type==float.class||type==Float.class){
return (float)((double)value);
}
if(type==java.util.Date.class){
return new Date((long)((double)value));
}
return value;
}
3 POI作业
3.1 创建poi工具类::实现通用化 可以操作任意类型
package com.zhiyou100.util;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import com.zhiyou100.entity.Student;
import com.zhiyou100.entity.Teacher;
public class PoiUtil {
public static void main(String[] args) throws Exception{
// Object obj="1234";
// System.out.println(obj.getClass());
// List<Object> list=new ArrayList<Object>();
// for (int i = 0; i <10; i++) {
// list.add(new Student(
// (int)(Math.random()*1000+2000),
// UUID.randomUUID().toString().substring(1, 5),
// (int)(Math.random()*10+15),
// Math.random()>0.5,
// new Date(2020-1900, (int)(Math.random()*12+1), (int)(Math.random()*30+1)),
// (int)(Math.random()*1000)/10.0f,
// "无名氏"+i,
// i+"123", i+"1.jpg"));
// }
// createExcel(list,"学生信息表2.xls");
List<Object> list=new ArrayList<Object>();
for (int i = 0; i <10; i++) {
list.add(
new Teacher(
i+100,
UUID.randomUUID().toString().substring(0, 5),
Math.random()>0.5?"男":"女"));
}
createExcel(list,"老师信息表1.xls");
}
//创建excel文件
//public static void createExcel(List<Object>,File file)throws Exception{
//使用反射把list中的对象写成表格的行
//表格标题是对象的类名
//表格列标题是属性名
public static void createExcel(List<Object> list,String fileName)throws Exception{
Class cla=list.get(0).getClass();
//1 创建工作薄:
HSSFWorkbook book=new HSSFWorkbook();
//2 创建sheet:表格对象
HSSFSheet sheet=book.createSheet(cla.getSimpleName());
//3 创建第一行:列标题
HSSFRow row0=sheet.createRow(0);
Field[] fields=cla.getDeclaredFields();//对象有多少个属性 表格就有多少列
for (int i = 0; i < fields.length; i++) {
Field field=fields[i];
field.setAccessible(true);
String fieldName=field.getName();
row0.createCell(i).setCellValue(fieldName);
}
//4 每个对象对应写成一行
for (int i = 0; i <list.size(); i++) {
Object obj=list.get(i);
//创建行
HSSFRow rowi=sheet.createRow(i+1);
for (int j = 0; j < fields.length; j++) {
Field field=fields[j];
Object fieldValue=field.get(obj);//获取属性的值
HSSFCell cellij=rowi.createCell(j);
if(field.getType()==Date.class){
CellStyle dateStyle=book.createCellStyle();
dateStyle.setDataFormat(book.createDataFormat().getFormat("yyyy-MM-dd"));
cellij.setCellStyle(dateStyle);
}
//cellij.setCellValue(fieldValue);
setCellValue(field,fieldValue,cellij);
}
}
book.write(new File("E:\\poi",fileName));
book.close();
}
//根据filed的类型把Object类型的值 转换为Field类型的值 然后给cell设置文本内容
private static void setCellValue(Field field,Object value,HSSFCell cell){
//需要的类型:boolean string date double
Class type=field.getType();
if(type==int.class||type==Integer.class){
cell.setCellValue((Integer)value);
}else if(type==short.class||type==Short.class){
cell.setCellValue((Short)value);
}else if(type==long.class||type==Long.class){
cell.setCellValue((Long)value);
}else if(type==boolean.class||type==Boolean.class){
cell.setCellValue((Boolean)value);
}else if(type==float.class||type==Float.class){
cell.setCellValue((Float)value);
}else if(type==char.class||type==Character.class){
cell.setCellValue((Character)value);
}else if(type==String.class){
cell.setCellValue((String)value);
}else if(type==byte.class||type==Byte.class){
cell.setCellValue((Byte)value);
}else if(type==double.class||type==Double.class){
cell.setCellValue((Double)value);
}else if(type==Date.class){
cell.setCellValue((Date)value);
}else{
throw new RuntimeException(type+"是不支持的类型!");
}
}
//读取excel文件
public static List<Object> readExcel(File file,String className)throws Exception{
//1 创建工作薄:读取源文件
HSSFWorkbook book=new HSSFWorkbook(new FileInputStream(file));
//2 获取第一个表格
HSSFSheet sheet=book.getSheet(className);
//3 获取第一行:列标题 对应的时类的属性名
HSSFRow row1=sheet.getRow(0);
//创建一个数组存储属性名
List<String> fieldNames=new ArrayList<>();
Iterator<Cell> it=row1.cellIterator();
while(it.hasNext()){
Cell cell=it.next();
fieldNames.add(cell.getStringCellValue());//存储列明:属性名
}
//遍历其他行
List<Object> listObj=new ArrayList<>();
Class cla=Class.forName("com.zhiyou100.entity."+className);
for (int i = 1; i < sheet.getLastRowNum(); i++) {
HSSFRow rowi=sheet.getRow(i);
//每行对应一个className类型的对象
Object obj=cla.newInstance();
for (int j = 0; j <rowi.getLastCellNum(); j++) {
Object fieldValue;
HSSFCell cellij=rowi.getCell(j);
//获取其值
//System.out.println(cellij.getCellStyle()+":"+cellij.getCellType()+":::"+j);
if(cellij.getCellType()==CellType.BOOLEAN){
fieldValue=cellij.getBooleanCellValue();
}else if(cellij.getCellType()==CellType.NUMERIC){
fieldValue=cellij.getNumericCellValue();
}else{
fieldValue=cellij.getStringCellValue();
}
//把值赋值给obj的属性
Field fieldj=cla.getDeclaredField(fieldNames.get(j));
fieldj.setAccessible(true);
fieldValue=changeValue(fieldj,fieldValue);//
fieldj.set(obj, fieldValue);
}
listObj.add(obj);
}
book.close();
return listObj;
}
//把value转换为field对应的类型:
private static Object changeValue(Field field,Object value){
Class type=field.getType();
if(type==int.class||type==Integer.class){
return (int)((double)value);
}
if(type==short.class||type==Short.class){
return (short)((double)value);
}
if(type==byte.class||type==Byte.class){
return (byte)((double)value);
}
if(type==long.class||type==Long.class){
return (long)((double)value);
}
if(type==float.class||type==Float.class){
return (float)((double)value);
}
if(type==java.util.Date.class){
return new Date((long)((double)value));
}
return value;
}
}
3.2 jsp页面:student_manager02.jsp
<h1>POI操作</h1>
<form action="<c:url value='/student/uploadExcel.action'/>" method="post" enctype="multipart/form-data">
<input type="file" name="studentSheet"/>
<input type="submit" value="excel表格上传"/>
</form><br/>
<a href="<c:url value='/student/downloadExcel.action'/>" >下载学生信息生成excel表格</a>
3.3 action
@RequestMapping("/uploadExcel.action")
public String uploadExcelMethod(@RequestParam("studentSheet") MultipartFile studentSheet,HttpServletRequest req)throws Exception{
//List<Object> readExcel(File file,String className)
File muDi=new File(studentSheet.getOriginalFilename());//创建一个目的文件 来保存上传的excel文件
studentSheet.transferTo(muDi);
//读取文件中的信息
List<Object> list=PoiUtil.readExcel(muDi, "Student");
//把list中的所有对象的信息保存到数据库中
for (Object object : list) {
Student stu=(Student)object;
studentService.addOne(stu);
}
req.setAttribute("message", "学生信息的excel表格上传成功!");
return "forward:/student/getAllFenYe.action";
}
@RequestMapping("/downloadExcel.action")
public ResponseEntity<byte[]> downloadExcelMethod(HttpServletRequest req)throws Exception{
//获取所有学生的信息
List<Student> list=studentService.getAll();
List<Object> listObj=new ArrayList<Object>();
for (Student s : list) {
listObj.add(s);
}
//创建excel文件
String fileName=System.currentTimeMillis()+"_学生信息表.xls";
PoiUtil.createExcel(listObj, fileName);
File yuan=new File("E:\\poi",fileName);
//获取文件的类型
String type=req.getServletContext().getMimeType(fileName);
byte[] arr=FileUtils.readFileToByteArray(yuan);
//创建heander对象 响应头
HttpHeaders headers=new HttpHeaders();
headers.set("Content-Type", type);
headers.set("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName, "utf-8"));
//获取源文件
//context.get
ResponseEntity<byte[]> entity=new ResponseEntity<byte[]>(arr,headers,HttpStatus.OK);
return entity;
}
3.4 有待优化的地方
- poi工具类中excel文件的目录 应该设置为servletcontent的初始化参数
- poi工具类应该指定为泛型类:这样写的参数为List 读的返回值为List
- poi中两个判断类型的方法 太low了 但没有更好的方法
4 实现事务管理
4.1在spring核心配置文件中添加事务自动注册的标签
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--添加tx标签的命名空间和xsd文件-->
<!-- 开启事务注册驱动 -->
<tx:annotation-driven/>
<!--3配置事务管理bean -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
</beans>
4.2 只在springmvc配置文件中注册扫描action包 在spring中注册扫描service包
<!-- 1通过context标签扫描包 -->
<context:component-scan base-package="com.zhiyou100.service"/>
<!-- 1通过context标签扫描包 -->
<context:component-scan base-package="com.zhiyou100.action"/>
4.3 更改添加的代码 让所有的添加都抛出异常: 并添加注解Transactional
@Transactional
public int addOne(Student stu) {
stu.setSpwd(MD5.getInstance().getMD5(stu.getSpwd()));
int hang=studentMapper.addOne(stu);
Student studentDb=studentMapper.getOneBySname(stu.getSname());
if(studentDb!=null){
throw new StudentCrudException("学生名字错误!");
}
return hang;
}
4.4 测试发现
出现异常:数据库没有添加成功
去掉注解:出现异常 数据库添加成功