JEEWEB具有代码生成功能,在阅读源码及使用其开发过程中,想将上传功能集成到代码生成模块,现将改动记录如下:
1.修改src/main/resources下的upload.properties和spring-mvc.xml文件:
将upload.properties中的upload.base.dir的值由upload改为../uploads,即将上传的文件所在路径由项目下的upload路径更改为与项目同级的文件uploads,这样项目重新部署的时候就不会影响到上传的文件;
修改spring-mvc.xml,将原先配置的上传文件(如下)
<!-- 支持上传文件 -->
<!-- 配置MultipartResolver 用于文件上传 使用spring的CommosMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8" p:maxUploadSize="${upload.max.size}" p:uploadTempDir="${upload.base.dir}/temp"/>
去掉
p:uploadTempDir="${upload.base.dir}/temp"
因为如果不去的话,会在启动时报错:
严重: Servlet [springMvc] in web application [/jeeweb] threw load() exception
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
PropertyAccessException 1:
org.springframework.beans.MethodInvocationException: Property 'uploadTempDir' threw exception; nested exception is java.lang.IllegalArgumentException: Given uploadTempDir [ServletContext resource [/../uploads/temp]] could not be created
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1170)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:922)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:82)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:62)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1489)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:672)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:543)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5266)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5554)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1263)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1948)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.IllegalArgumentException: Given uploadTempDir [ServletContext resource [/../uploads/temp]] could not be created
at org.springframework.web.multipart.commons.CommonsFileUploadSupport.setUploadTempDir(CommonsFileUploadSupport.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1157)
... 37 more
几经查询,没找到有效解决方法,但发现去掉这项不影响使用,且启动也不报错。。
2.在src/main/webapp/static/common/js路径下添加ajaxfileupload.js文件,通过ajaxfileupload上传,可以从下方链接中下载:ajaxFileUpload 报这错jQuery.handleError is not a function
添加完后,在src/main/resources/mapper/tags/html路径下的vendors-js-html-component.xml中配置,添加:
<js name="ajaxfileupload">
<![CDATA[
<!-- ajaxfileupload-->
<script src="${staticPath}/common/js/ajaxfileupload.js"></script>
]]>
</js>
3.修改src/main/resources/codegen/template/code自动生成代码模板中的list和controller:
对于viewListTemplate.ftl添加:
<html:js name="ajaxfileupload" />
<script type="text/javascript">
function uploads(){
$.ajaxFileUpload
(
{
url:"${r'${adminPath}'}/${moduleName}/${entityName?lower_case}/uploads", //用于文件上传的服务器端请求地址
type:"POST",
secureuri: false, //是否需要安全协议,一般设置为false
fileElementId: 'upload1', //文件上传域的ID
dataType: 'json', //返回值类型 一般设置为json,content
success: function (data, status) //服务器成功响应处理函数
{
if(data.msg!='success'){
alert(data.msg);
}
location.reload(true);
},
error: function (data, status, e)//服务器响应失败处理函数
{
alert("error:"+e);
}
}
);
return false;
}
</script>
<grid:toolbar title="上传" btnclass="btn-warning" icon="fa-database" οnclick="$('#upload1').click();"/>
<input type="file" id="upload1" name="upload1" οnchange="uploads()" style="display:none" />
既添加了上传按钮,并写好了js,接着修改ControllerTemplate.ftl模板,添加:
import cn.jeeweb.modules.sys.service.IAttachmentService;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import java.util.Iterator;
import org.springframework.web.multipart.MultipartFile;
import cn.jeeweb.modules.sys.entity.Attachment;
import cn.jeeweb.core.utils.ExcelReader;
import java.util.ArrayList;
导入需要的类,以及注入需要的service,
@Autowired
protected IAttachmentService attachmentService;
添加uploads方法:
@RequestMapping(value = "uploads", method = { RequestMethod.GET, RequestMethod.POST })
private @ResponseBody String uploads(HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject json = new JSONObject();
String msg = "success";
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
if (multipartResolver.isMultipart(request)) { // 判断request是否有文件上传
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> ite = multiRequest.getFileNames();
while (ite.hasNext()) {
MultipartFile file = multiRequest.getFile(ite.next());
Attachment attachment = attachmentService.upload(request, file);
String proPath=request.getServletContext().getRealPath("/");
String filePath = proPath + attachment.getFilepath();
String headPath = filePath.substring(0, filePath.indexOf("/uploads"))
+"/uploads/template/userUpload.xlsx";//template后面自行替换模板(表头)
List<List<String>> dataList = ExcelReader.readXlsx(filePath);
List<String> headList = ExcelReader.readHeader(headPath);
List<${entityName?cap_first}> list = new ArrayList<${entityName?cap_first}>();//要插入数据库的数据
if(dataList.size()>0){
for(int i=0;i<dataList.size();i++){
List<String> rows = dataList.get(i);
if(i==0){
if(rows.size()==headList.size()){
for(int j=0;j<headList.size();j++){
if(headList.get(j).equals(rows.get(j))){
continue;
}else{
msg = "fail:your table's header is mismatch!";
json.put("msg", msg);
return json.toString();
}
}
}else{
msg = "fail:your table header's length is not right";
json.put("msg", msg);
return json.toString();
}
}else{
${entityName?cap_first} user = new ${entityName?cap_first}();
//按顺序取值,放入对象中,添加到list里
/**user.setId(rows.get(0).equals("")?null:Integer.parseInt(rows.get(0)));
user.setName(rows.get(1));
user.setSex(rows.get(2));
user.setAge(rows.get(3));
user.setHeight(rows.get(4));
list.add(user);*/
}
}
}
if(list.size()>0){
${entityName?uncap_first}Service.insertBatch(list);
}
continue;
}
}
json.put("msg", msg);
return json.toString();
}
对应的tree和onetomany路径下的两个模板修改方式如上一致。
上传的模板放在了uploads/template路径下,当上传文件后,会读取上传文件的第一行与模板的第一行比对,确定文件格式正确,才会继续读取文件内容,插入数据库。4.上文涉及到的工具类ExcelReader.java见下,需要添加到cn.jeeweb.core.utils包下:
package cn.jeeweb.core.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
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.Row;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelReader {
public static List<List<String>> readXlsx(String path) throws Exception{//String path
InputStream is = new FileInputStream(path);
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
List<List<String>> result = new ArrayList<List<String>>();
//循环每一页,并处理当前循环页
for(int numSheet = 0;numSheet < xssfWorkbook.getNumberOfSheets();numSheet++){
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet);
if(xssfSheet == null){
continue;
}
int lastRow = getEmptrRow(xssfSheet);//hssfSheet.getLastRowNum()
XSSFRow row = xssfSheet.getRow(0);
int minCol = row.getFirstCellNum();
int maxCol = row.getLastCellNum();
//处理当前页,循环读取每一行
for(int rowNum = 0; rowNum < lastRow;rowNum++){
XSSFRow xssfRow = xssfSheet.getRow(rowNum);
List<String> rowList = new ArrayList<String>();
//遍历该行,获取处理每个cell元素
for(int col = minCol;col<maxCol;col++){
XSSFCell cell = xssfRow.getCell(col);
if(cell == null){
rowList.add("");
continue;
}
rowList.add(getStringVal(cell));
}
result.add(rowList);
}
}
is.close();
return result;
}
/**
* 获取最后一行
*/
public static int getEmptrRow(XSSFSheet sheet) {
int rownumber = 0;
if (sheet != null) {
Iterator<Row> rowiter = sheet.iterator();
while (rowiter.hasNext()) {
Row row = rowiter.next();
if (row != null) {
String rowValue = null;
Iterator<Cell> iter = row.iterator();
while (iter.hasNext()) {
Cell cell = iter.next();
if (cell.getCellType() == 0) {
rowValue += cell.getNumericCellValue();
} else {
rowValue += cell.getStringCellValue();
}
}
if (rowValue != null && !rowValue.equalsIgnoreCase("null")) {
rownumber = row.getRowNum();
}
}
}
}
return rownumber + 1;
}
public static List<String> readHeader(String path) throws Exception{
InputStream is = new FileInputStream(path);
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);
XSSFRow xssfRow = xssfSheet.getRow(0);
int minCol = xssfRow.getFirstCellNum();
int maxCol = xssfRow.getLastCellNum();
List<String> rowList = new ArrayList<String>();
//遍历该行,获取处理每个cell元素
for(int col = minCol;col<maxCol;col++){
XSSFCell cell = xssfRow.getCell(col);
if(cell == null){
rowList.add("");
continue;
}
rowList.add(getStringVal(cell));
}
is.close();
return rowList;
}
public static String getStringVal(XSSFCell cell){
switch(cell.getCellType()){
case Cell.CELL_TYPE_BOOLEAN:
return cell.getBooleanCellValue()?"TRUE":"FALSE";
case Cell.CELL_TYPE_FORMULA:
return cell.getCellFormula();
case Cell.CELL_TYPE_NUMERIC:
cell.setCellType(Cell.CELL_TYPE_STRING);
return cell.getStringCellValue();
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
default:
return "";
}
}
}
至此,自动生成代码时,即可在列表页,自带上传功能,可以上传excel文件,插入数据到数据库,只是要自定义模板
的表头。
下方另附一些修改其他小地方的方法:
1.修改列表页默认一页显示的行数,需更改的地方:
(1)cn.jeeweb.core.model.PageJson.java中的:
private long rows = 10;// 每页显示记录数
(2)cn.jeeweb.core.tags.grid.DataGridTag.java中的:
private int rowNum = 10; // 这个参数是要被传递到后台,树结构时候,rowNum无效
2.在自动生成代码功能中,数据库字段与java字段映射部分,java字段类型添加Long类型方法:
(1)cn.jeeweb.modules.codegen.codegenerator.data.AttributeInfo.java中:
private String[] baseTypes = { "String", "Double", "Text", "Date", "Blob", "Short", "Integer", "Boolean","Long" };
添加Long;
(2)cn.jeeweb.modules.codegen.controller.TableController.java中添加Long:
private String[] types = { "String", "Double", "Text", "Date", "Blob", "Short", "Integer", "Boolean", "User","Long",
"this" };
(3)cn.jeeweb.modules.codegen.entity.Column.java中添加Long:
private String[] baseTypes = { "String", "Double", "Text", "Date", "Blob", "Short", "Integer", "Boolean","Long" };
即可。
参考博客:
1.ajaxFileUpload 报这错jQuery.handleError is not a function
3.ajaxfileupload 始终不执行success 只执行error方法;SyntaxError: expected expression, got '<