diff --git a/.gitignore b/.gitignore index 8ce455a205841818b691c445a2ab10cd828740a3..50150185744158a0475997694474f214b5beca5e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ *.iws *.iml *.ipr -。DS_Store +.DS_Store */target/* */.settings/* */logs/* diff --git a/Dockerfile b/Dockerfile index 6c5288c80c238907b97cfcdcba2d0236b60b5ffe..182a00570b088e4400c4dc852dc055616e20afe5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,22 @@ -FROM java:8 -ADD antdsp-admin/target/antdsp-admin-0.0.1.jar antdsp-min.jar -ENTRYPOINT ["java","-jar","/antdsp-min.jar"] \ No newline at end of file +FROM alpine + +MAINTAINER lijiantao + +# 拷贝jdk、maven 文件 +ADD jdk1.8.0_211 /usr/local/jdk +ADD apache-maven-3.6.1 /usr/local/maven + +#安装alpine下 jdk 底层 Glibc +RUN apk --no-cache add ca-certificates wget +RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub +RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-2.29-r0.apk +RUN apk add glibc-2.29-r0.apk + +#删除 +RUN rm glibc-2.29-r0.apk + +#环境变量 +ENV JAVA_HOME=/usr/local/jdk +ENV CLASSPATH=${JAVA_HOME}/lib/ +ENV MAVEN_HOME=/usr/local/maven +ENV PATH=.:${JAVA_HOME}/bin:${MAVEN_HOME}/bin:$PATH diff --git a/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspErrorException.java b/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspErrorException.java new file mode 100644 index 0000000000000000000000000000000000000000..adcfa18d6b47d642675f0a963a6c880636bcff14 --- /dev/null +++ b/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspErrorException.java @@ -0,0 +1,12 @@ +package com.antdsp.common.exception; + +public class AntdspErrorException extends RuntimeException { + + public AntdspErrorException() { + super(); + } + + public AntdspErrorException(String message) { + super(message); + } +} diff --git a/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspException.java b/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspException.java index 5feefc9cd7ac5ecd044744daa8169ae1b566ff47..0f99d5cb1be51931437d0f1b54c99ed0e66074f3 100644 --- a/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspException.java +++ b/antdsp-admin/src/main/java/com/antdsp/common/exception/AntdspException.java @@ -33,4 +33,10 @@ public class AntdspException extends RuntimeException{ public AntdspResponse captchaException(CaptchaException e) { return new AntdspResponse( ResponseCode.ERROR , false , e.getMessage()); } + + @ExceptionHandler(value= {AntdspErrorException.class}) + @ResponseBody + public AntdspResponse errorException(AntdspErrorException e) { + return new AntdspResponse( ResponseCode.ERROR , false , e.getMessage()); + } } diff --git a/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/ArticleApi.java b/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/ArticleApi.java index 5221d27060de2d84926a012ac96698512100d794..ee8ae8a4005c7f1bb7022643b6109f57b8d4897c 100644 --- a/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/ArticleApi.java +++ b/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/ArticleApi.java @@ -10,7 +10,9 @@ import javax.persistence.criteria.Root; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.domain.Specification; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -60,6 +62,7 @@ public class ArticleApi { } @PostMapping("") + @Transactional public AntdspResponse add(@RequestBody Article article) { User current = ShiroUtils.currentUser(); @@ -71,6 +74,7 @@ public class ArticleApi { } @PutMapping("/{id:\\d+}") + @Transactional public AntdspResponse update(@RequestBody Article article) { Article oldArticle = articleJpa.findById(article.getId()).orElse(null); if(oldArticle == null) { @@ -88,4 +92,17 @@ public class ArticleApi { return AntdspResponse.success(); } + + @DeleteMapping("/{id:\\d+}") + @Transactional + public AntdspResponse del(@PathVariable("id") Long id) { + + Article oldArticle = articleJpa.findById(id).orElse(null); + if(oldArticle == null) { + return AntdspResponse.error("为找到对应信息"); + } + + this.articleJpa.delete(oldArticle); + return AntdspResponse.success(); + } } diff --git a/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/SystemLogApi.java b/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/SystemLogApi.java index 59c90ae677fc70213f95319b0873d9087e8c7f97..8237faf8867ba0e9692f4a250d27eae83eefbe92 100644 --- a/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/SystemLogApi.java +++ b/antdsp-admin/src/main/java/com/antdsp/web/rest/operation/SystemLogApi.java @@ -1,41 +1,125 @@ package com.antdsp.web.rest.operation; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.domain.Specification; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.antdsp.common.annotation.OperationLog; +import com.antdsp.common.exception.AntdspErrorException; import com.antdsp.common.pagination.PaginationData; import com.antdsp.dao.jpa.system.SystemLogJpa; import com.antdsp.data.entity.system.SystemLog; +import com.antdsp.utils.excelutil.Column; +import com.antdsp.utils.excelutil.ColumnRender; +import com.antdsp.utils.excelutil.ExcelUtil; @RestController @RequestMapping("/operation/log") public class SystemLogApi { + private static final Logger logger = LoggerFactory.getLogger(SystemLogApi.class); + @Autowired private SystemLogJpa systemLogJpa; @GetMapping - public PaginationData list(int page, int count){ + @OperationLog(name="日志信息") + public PaginationData list(int page, int count, Long startTime, Long endTime){ Specification specification = new Specification() { @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { - return null; + + List predicates = new ArrayList<>(); + if(startTime != null) { + + if(endTime != null) { + predicates.add(criteriaBuilder.between(root.get("created") , new Date( startTime) , new Date (endTime))); + }else { + predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("created"), new Date(startTime))); + } + }else if(endTime != null){ + predicates.add(criteriaBuilder.lessThan(root.get("lastModified"),new Date(endTime))); + } + + return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); } }; return this.systemLogJpa.list(specification, page, count); } + + @GetMapping("/export") + public void export(HttpServletResponse response, Long startTime, Long endTime) { + + Specification specification = new Specification() { + + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, + CriteriaBuilder criteriaBuilder) { + List predicates = new ArrayList<>(); + if(startTime != null) { + + if(endTime != null) { + predicates.add(criteriaBuilder.between(root.get("created") , new Date( startTime) , new Date (endTime))); + }else { + predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("created"), new Date(startTime))); + } + }else if(endTime != null){ + predicates.add(criteriaBuilder.lessThan(root.get("lastModified"),new Date(endTime))); + } + + return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); + } + + }; + + List data = this.systemLogJpa.findAll(specification); + List columns = new ArrayList<>(); + + columns.add(new Column("用户名", "optorName", null)); + columns.add(new Column("用户操作", "optName", null)); + columns.add(new Column("请求URI", "optURI", null)); + columns.add(new Column("请求方式", "optType", null)); + columns.add(new Column("请求参数", "optDetail", null)); + columns.add(new Column("耗时(毫秒)", "runTime", new ColumnRender() { + @Override + public String render(String value) { + return value + "ms"; + } + + })); + columns.add(new Column("操作IP", "optorIp", null)); + columns.add(new Column("创建时间", "created", null)); + + response.setContentType("application/vnd.ms-excel"); + response.setHeader("Content-disposition", "attachment; filename=systemlog.xlsx"); + + try { + ExcelUtil.dataToResponse(columns, data, response.getOutputStream()); + }catch(Exception e) { + logger.error("系统日志下载失败", e); + throw new AntdspErrorException("系统日志下载失败"); + } + } } diff --git a/antdsp-admin/src/main/web/src/pages/Login/Index.js b/antdsp-admin/src/main/web/src/pages/Login/Index.js index 0b81d1760f21b7f7414e9c40075570892ebab046..6cd01b7332cd231eed0eecc988f1621b2d126ec9 100644 --- a/antdsp-admin/src/main/web/src/pages/Login/Index.js +++ b/antdsp-admin/src/main/web/src/pages/Login/Index.js @@ -19,6 +19,14 @@ export default class Login extends PureComponent{ captcha: moment().milliseconds() } + componentDidMount(){ + document.body.addEventListener("keypress", (e)=>{ + if(e.keyCode != 13) return ; + + this.handlerLogin(); + }); + } + handlerLogin=()=>{ const { form, dispatch } = this.props; diff --git a/antdsp-admin/src/main/web/src/pages/Operation/Article/Index.js b/antdsp-admin/src/main/web/src/pages/Operation/Article/Index.js index 37895d808e32e503ec175f86b13d9c308814afdc..c165c4ad28e5cfaf70b8a96040d97b91cd00ebad 100644 --- a/antdsp-admin/src/main/web/src/pages/Operation/Article/Index.js +++ b/antdsp-admin/src/main/web/src/pages/Operation/Article/Index.js @@ -1,7 +1,7 @@ import { PureComponent, Fragment } from "react"; import PageHeaderWrapper from "@/components/PageHeaderWrapper"; import Block from "@/custom/Block"; -import { Table, Divider, Popconfirm, Card, Button } from "antd"; +import { Table, Divider, Popconfirm, Card, Button, message } from "antd"; import moment from "moment"; import { connect } from "dva"; import router from 'umi/router'; @@ -13,7 +13,7 @@ import router from 'umi/router'; export default class ArticleIndex extends PureComponent{ state = { - formValues: { + formValue: { page: 1, count: 10, } @@ -24,7 +24,7 @@ export default class ArticleIndex extends PureComponent{ dispatch({ type: 'article/fetchAll', payload: { - ...this.state.formValues, + ...this.state.formValue, } }) } @@ -56,6 +56,30 @@ export default class ArticleIndex extends PureComponent{ router.push("/operation/article/0"); } + handlerDelOnClick=(id)=>{ + const { dispatch } = this.props; + + dispatch({ + type: 'article/del', + payload: { + id: id + }, + callback:(result)=>{ + if(result.success){ + message.info(result.message); + dispatch({ + type: 'article/fetchAll', + payload: { + ...this.state.formValue + }, + }); + }else { + message.error(result.message); + } + } + }); + } + render(){ const columns = [{ @@ -77,7 +101,7 @@ export default class ArticleIndex extends PureComponent{ router.push(`/operation/article/${record.id}`); }}>编辑 - + {this.handlerDelOnClick(record.id)}}> 删除 diff --git a/antdsp-admin/src/main/web/src/pages/Operation/Article/models/article.js b/antdsp-admin/src/main/web/src/pages/Operation/Article/models/article.js index 8cbd57502410586266217a8b1239c9035a9780d6..5db1db3102b93aa3ef5f173df147c99bc962542e 100644 --- a/antdsp-admin/src/main/web/src/pages/Operation/Article/models/article.js +++ b/antdsp-admin/src/main/web/src/pages/Operation/Article/models/article.js @@ -2,7 +2,8 @@ import { fetchAllArticle, fetchArticleById, addArticle, - updateArticle + updateArticle, + delArticle } from "@/services/operation" export default { @@ -45,6 +46,11 @@ export default { }else { response = yield call(updateArticle, Article); } + if(callback) callback(response); + }, + *del({payload, callback},{call}){ + const response = yield call(delArticle, payload); + if(callback) callback(response); } }, diff --git a/antdsp-admin/src/main/web/src/pages/Operation/Log/Index.js b/antdsp-admin/src/main/web/src/pages/Operation/Log/Index.js index d3b46762e9f52644f1ce0c345a7327ac45766e3d..805412582c2a87ab29f8d43c8634ea753ca40df6 100644 --- a/antdsp-admin/src/main/web/src/pages/Operation/Log/Index.js +++ b/antdsp-admin/src/main/web/src/pages/Operation/Log/Index.js @@ -2,11 +2,15 @@ import { PureComponent } from "react"; import { connect } from 'dva'; import PageHeaderWrapper from "@/components/PageHeaderWrapper"; import Block from "@/custom/Block"; -import { Form, Table, Card } from "antd"; +import { Form, Table, Card, Button, DatePicker } from "antd"; import moment from "moment"; +import qs from 'qs'; const FormItem = Form.Item; +const { RangePicker } = DatePicker; +const dateFormat = 'YYYY-MM-DD'; + @connect(({ operlog , loading })=>({ operlog, loading: loading.models.operlog @@ -56,9 +60,48 @@ export default class SystemLog extends PureComponent{ }); } + handlerQueryOnClick=()=>{ + + const { form, dispatch } = this.props; + + form.validateFields((err, fieldsValue) => { + if(err) return ; + + let { formValues } = this.state; + + + if(fieldsValue.datatime){ + + const datatime = fieldsValue.datatime; + formValues = { + ...formValues, + startTime: moment(datatime[0].format(dateFormat)).valueOf(), + endTime: moment(datatime[1].format(dateFormat)).valueOf(), + } + } + this.setState({formValues: formValues}); + dispatch({ + type: 'operlog/fetchAll', + payload: { + ...formValues + } + }) + }); + } + + handlerDownOnclick=()=>{ + const { dispatch } =this.props; + dispatch({ + type: 'operlog/download', + payload: { + ...this.state.formValues + } + }) + } + render(){ - const { operlog:{ LogList} , loading } = this.props; + const { operlog:{ LogList} , loading, form: {getFieldDecorator} } = this.props; const columns = [{ title: '用户名', @@ -75,7 +118,11 @@ export default class SystemLog extends PureComponent{ },{ title: '请求参数', dataIndex: 'optDetail', - width: '100px', + render: (text, record) => ( +
+ {text} +
+ ), },{ title: '耗时', dataIndex: 'runTime', @@ -91,9 +138,20 @@ export default class SystemLog extends PureComponent{ return ( - + 导出报表}> - +
+ + {getFieldDecorator('datatime')( + + )} + + + + +
org.springframework.bootspring-boot-starter-data-jpa + + + + org.apache.poi + poi + 3.14 + \ No newline at end of file diff --git a/antdsp-core/src/main/java/com/antdsp/common/pagination/Pagination.java b/antdsp-core/src/main/java/com/antdsp/common/pagination/Pagination.java index eae17de9f6e305c3b6850d0198f5cdf3ab0c9a0f..f299b8d2f1e1ce9ff1bd9b414d72a24f2d8385ea 100644 --- a/antdsp-core/src/main/java/com/antdsp/common/pagination/Pagination.java +++ b/antdsp-core/src/main/java/com/antdsp/common/pagination/Pagination.java @@ -18,6 +18,8 @@ public class Pagination { */ private int current; + private boolean showSizeChanger; + /** * 总条数 */ @@ -30,6 +32,13 @@ public class Pagination { public Pagination(int current, Long total) { this.current = current; this.total = total; + showSizeChanger = true; + } + + public Pagination(int current, Long total, boolean showSizeChanger) { + this.current = current; + this.total = total; + this.showSizeChanger = showSizeChanger; } public int getCurrent() { @@ -47,6 +56,14 @@ public class Pagination { public void setTotal(Long total) { this.total = total; } + + public boolean isShowSizeChanger() { + return showSizeChanger; + } + + public void setShowSizeChanger(boolean showSizeChanger) { + this.showSizeChanger = showSizeChanger; + } } diff --git a/antdsp-core/src/main/java/com/antdsp/utils/excelutil/Column.java b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/Column.java new file mode 100644 index 0000000000000000000000000000000000000000..da7ffd848afc199053bca0e4b9d85d4fe2caaaed --- /dev/null +++ b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/Column.java @@ -0,0 +1,64 @@ +package com.antdsp.utils.excelutil; + +import org.springframework.util.StringUtils; + +public class Column { + + /** + * 列头显示文字 + */ + private String title; + + /** + * 对应的实体类字段 + */ + private String field; + + private ColumnRender render; + + private String getterName; + + public Column(String title, String field, ColumnRender render) { + this.title = title; + this.field = field; + this.render = render; + this.setGetterName(field); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public ColumnRender getRender() { + return render; + } + + public void setRender(ColumnRender render) { + this.render = render; + } + + public String getGetterName() { + return getterName; + } + + private void setGetterName(String getterName) { + if(!StringUtils.isEmpty(getterName)) { + + this.getterName = "get"+field.substring(0, 1).toUpperCase()+field.substring(1,field.length()); + } + } + + +} diff --git a/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ColumnRender.java b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ColumnRender.java new file mode 100644 index 0000000000000000000000000000000000000000..e2c13e774eabf71f5d60cc7dd98fd9d8fcaa320f --- /dev/null +++ b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ColumnRender.java @@ -0,0 +1,12 @@ +package com.antdsp.utils.excelutil; + +public interface ColumnRender { + + default String render(String value) { + return value; + } + + default String render(String value , Object record) { + return render(value); + } +} diff --git a/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ExcelUtil.java b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ExcelUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..77708f223f7b5e704249df816e70c761373648fe --- /dev/null +++ b/antdsp-core/src/main/java/com/antdsp/utils/excelutil/ExcelUtil.java @@ -0,0 +1,60 @@ +package com.antdsp.utils.excelutil; + +import java.io.OutputStream; +import java.util.List; + +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.springframework.util.StringUtils; + +public class ExcelUtil { + + public static void dataToExcel(List columns , List data, HSSFWorkbook hwb) throws Exception { + + HSSFSheet sheet = hwb.createSheet("sheet1"); + HSSFRow rowhead = sheet.createRow( 0); + + //header + for (int i = 0; i < columns.size(); i++) { + String titleText = columns.get(i).getTitle(); + rowhead.createCell(i).setCellValue(titleText); + } + + Class dtoClass ; + if(data!=null && data.size()>0) { + dtoClass = data.get(0).getClass(); + }else { + return ; + } + + //行 + for(int j = 0 ; j void dataToResponse(List columns , List data, OutputStream output) throws Exception { + HSSFWorkbook hwb = new HSSFWorkbook(); + dataToExcel(columns, data, hwb); + hwb.write(output); + } + + +}