ruoyi框架使用总结(一)
1. 前后端返回longint数据精度缺失?
处理springboot 前后端精度问题?
数据转换,长整型和时间格式化?
https://www.cnblogs.com/mfser/p/10138648.html
https://www.freesion.com/article/1548455900/
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.cms2.common.annotation.Excel;
import com.cms2.common.core.domain.BaseEntity;
/**
* 官网的banner图对象 ow_banner
*
* @author cms2
* @date 2021-03-09
*/
public class OwBanner extends BaseEntity
{
private static final long serialVersionUID = 1L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
}
2. 咋样引入一个不知道版本号的jar包?
https://www.freesion.com/article/1548455900/
3. 优化若依框架自带的 图片上传ui和功能?
3.1 我们要先定义一个 上传图片的接口
- xxx-commons/utils/file/FtpFileUploadUtils.java 定义工具类
package com.cms2.common.utils.file;
import com.alibaba.fastjson.JSONObject;
import com.cms2.common.utils.DateUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
/**
* @description:ftp文件上传工具
*/
public class FtpFileUploadUtils {
//ftp服务器ip地址
private static final String FTP_ADDRESS = "";
//端口号
private static final int FTP_PORT = 21;
//用户名
private static final String FTP_USERNAME = "";
//密码
private static final String FTP_PASSWORD = "";
//图片路径
private static final String FTP_BASE_PATH = "/usr/local/images/";
public static JSONObject uploadRemoteFile(String typeDir,String urlString){
URL url = null;
try {
url = new URL(urlString);
//打开链接
URLConnection conn = url.openConnection();
//超时响应时间为5秒
conn.setConnectTimeout(5 * 1000);
//通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
return uploadFile(typeDir,"xxx.png",inStream);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static JSONObject uploadFile(String typeDir, String originFileName, InputStream input) {
JSONObject json = new JSONObject();
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF8");
try {
int reply;
ftp.connect(FTP_ADDRESS, FTP_PORT);
ftp.login(FTP_USERNAME, FTP_PASSWORD);
// ftp.enterLocalPassiveMode();
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return json;
}
String timePath = fmtTimeFilePath(typeDir);
makeDir(ftp,timePath,FTP_BASE_PATH);
String finalPath = FTP_BASE_PATH +"/"+ timePath;
String fileExt = originFileName.substring(originFileName.lastIndexOf("."));
/*新文件名*/
String newUploadFileName = System.nanoTime() + fileExt;
ftp.makeDirectory(finalPath);
ftp.changeWorkingDirectory(finalPath);
ftp.storeFile(newUploadFileName, input);
input.close();
ftp.logout();
json.put("url","/images"+timePath+newUploadFileName);
json.put("filePath",timePath+newUploadFileName);
json.put("fileName",newUploadFileName);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return json;
}
public static boolean makeDir(FTPClient ftp,String finalPath,String basePath) throws IOException {
// 切换到上传目录
if (!ftp.changeWorkingDirectory(finalPath)) {
// 如果目录不存在创建目录
String[] dirs = finalPath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) {
continue;
}
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
return true;
}
/**
* 格式化文件夹格式 采用时间
* @param typeDir
* @return
*/
public static String fmtTimeFilePath(String typeDir) {
String timePath = DateUtils.getCurrentYear() + "/" + DateUtils.getCurrentMonth() + "/" + DateUtils.getCurrentDay();
return "/"+typeDir +"/"+ timePath+"/";
}
}
3.2 在 xxx-admin/controller/common/CommonController.java 定义通用ftp上传的方法
/**
* 通用FTP上传
*/
@PostMapping("/common/ftp/upload")
@ResponseBody
public AjaxResult ftpUploadFile(MultipartFile file, String typeDir) throws Exception {
try {
// 上传并返回新文件名称
String fileName = file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
String url = null;
JSONObject json = FtpFileUploadUtils.uploadFile(typeDir, fileName, inputStream);
AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", json.get("fileName"));
ajax.put("url", IMG_PATH + json.get("url"));
return ajax;
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
3.3 模板使用 上传图片的插件;当前模板引入对应的dragImgUpload.js插件
<div class="form-group">
<label class="col-sm-3 control-label">banner图片:</label>
<div class="col-sm-8">
<input id="url" name="url" class="form-control" type="hidden">
<div id="drop_area"></div>
</div>
</div>
<script>
var dragImgUpload = new DragImgUpload("#drop_area",{
callback:function (files) {
//回调函数,可以传递给后台等等
var file = files[0];
var data = new FormData();
data.append("file", file);
data.append("typeDir","ow_navigation");
$.ajax({
type: "POST",
url: ctx + "common/ftp/upload",
data: data,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
$("#url").val(result.url);
} else {
$.modal.alertError(result.msg);
}
},
error: function(error) {
$.modal.alertWarning("图片上传失败。");
}
});
}
})
});
</script>
3.4 通过jquery封装简单版上传图片的插件 dragImgUpload.js
function DragImgUpload(id,options) {
this.me = $(id);
var defaultOpt = {
boxWidth:'200px',
boxHeight:'auto'
}
this.preview = $('<div id="preview"><img src="/img/upload.png" class="img-responsive" style="width: 100%;height: auto;" alt="" title=""> </div>');
this.opts=$.extend(true, defaultOpt,{
}, options);
this.init();
this.callback = this.opts.callback;
}
//定义原型方法
DragImgUpload.prototype = {
init:function () {
var imageUrl = $("#thumbnail").val();
if(imageUrl == null || imageUrl == ""){
this.me.append(this.preview);
}
this.me.append(this.fileupload);
this.cssInit();
this.eventClickInit();
},
cssInit:function () {
this.me.css({
'width':this.opts.boxWidth,
'height':this.opts.boxHeight,
'border':'1px solid #cccccc',
'padding':'10px',
'cursor':'pointer'
})
this.preview.css({
'height':'100%',
'overflow':'hidden'
})
},
onDragover:function (e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
},
onDrop:function (e) {
var self = this;
e.stopPropagation();
e.preventDefault();
var fileList = e.dataTransfer.files; //获取文件对象
// do something upload
if(fileList.length == 0){
return false;
}
//检测文件是不是图片
if(fileList[0].type.indexOf('image') === -1){
alert("您拖的不是图片!");
return false;
}
//拖拉图片到浏览器,可以实现预览功能
var img = window.URL.createObjectURL(fileList[0]);
var filename = fileList[0].name; //图片名称
var filesize = Math.floor((fileList[0].size)/1024);
if(filesize>500){
alert("上传大小不能超过500K.");
return false;
}
self.me.find("img").attr("src",img);
self.me.find("img").attr("title",filename);
if(this.callback){
this.callback(fileList);
}
},
eventClickInit:function () {
var self = this;
this.me.unbind().click(function () {
self.createImageUploadDialog();
})
var dp = this.me[0];
dp.addEventListener('dragover', function(e) {
self.onDragover(e);
});
dp.addEventListener("drop", function(e) {
self.onDrop(e);
});
},
onChangeUploadFile:function () {
var fileInput = this.fileInput;
var files = fileInput.files;
var file = files[0];
var img = window.URL.createObjectURL(file);
var filename = file.name;
this.me.find("img").attr("src",img);
this.me.find("img").attr("title",filename);
if(this.callback){
this.callback(files);
}
},
createImageUploadDialog:function () {
var fileInput = this.fileInput;
if (!fileInput) {
//创建临时input元素
fileInput = document.createElement('input');
//设置input type为文件类型
fileInput.type = 'file';
//设置文件name
fileInput.name = 'ime-images';
//允许上传多个文件
fileInput.multiple = true;
fileInput.onchange = this.onChangeUploadFile.bind(this);
this.fileInput = fileInput;
}
//触发点击input点击事件,弹出选择文件对话框
fileInput.click();
}
}
4. 使用代码生成和菜单管理?;咋样同时生成自定义包名的文件?
参考文献
* 先使用菜单管理创建预定好的菜单
* 创建表,然后通过代码生成导入表,配置好参数,生成对应的 controller,service, dao,mapper, template
5. 咋样创建带有层级结构的树形表格?实现有具体层级表结构?
通过代码生成器,创建树形表格,选择id,和pid配置,很简单。
```html
<div class="form-group">
<label class="col-sm-3 control-label">父导航id:</label>
<div class="col-sm-8">
<div class="input-group">
<input id="treeId" name="pid" type="hidden" ="${owNavigation?.id}"/>
<input class="form-control" type="text" onclick="selectOwNavigationTree()" id="treeName" readonly="true" th:value="${owNavigation?.name}">
<span class="input-group-addon"><i class="fa fa-search"></i></span>
</div>
</div>
</div>
```
6. 进入首页如何自动展开某菜单?
例如,进入自动打开用户管理,调用applyPath,填入你请求菜单对应的url地址。
applyPath("/system/role")
7. 做下拉框的三级联动效果?咋样在模板调用 service层数据?使用行内获取值语法[[${@xxx.yyy()}]]?
- 当一个业务线需要其他业务线支撑完成
比如:官网内容管理新增和编辑,需要导航管理中的导航分类一级 二级绑定时,需要查询导航管理分类级别 显示到 内容管理的页面中。
- 引入第三放js css,
<!--下拉框树形级联效果-->
<div th:fragment="bootstrap-cascader-min-css">
<link th:href="@{/ajax/libs/bootstrap-cascader/css/bootstrap-cascader.min.css}" rel="stylesheet"/>
</div>
<div th:fragment="bootstrap-cascader-min-js">
<script th:src="@{/ajax/libs/bootstrap-cascader/js/bootstrap-cascader.min.js}"></script>
</div>
- 使用模板地方
<div class="form-group">
<label class="col-sm-3 control-label">导航类别:</label>
<div class="col-sm-8">
<!--<input name="navId" class="form-control" type="text">-->
<div id="navType"></div>
</div>
</div>
<script>
// 引入自定义的 service 层返回的 加工后的数据
var navTypes = [[${@navTypeService.getList()}]];
console.log(navTypes);
$(function() {
$("#navType").bsCascader({
openOnHover: true,
loadData: function(openedItems, callback) {
callback(navTypes)
}
})
})
</script>
- 自定义的service 写在 xxx-framework/.../service
package com.cms2.framework.web.service;
import com.cms2.common.core.domain.Ztree;
import com.cms2.system.domain.OwNavTypeTree;
import com.cms2.system.service.IOwNavigationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @description: 导航分类 service
*/
@Service("navTypeService")
public class NavTypeService {
@Autowired
public IOwNavigationService owNavigationService;
public List<OwNavTypeTree> getList() {
List<OwNavTypeTree> list = owNavigationService.getTreeNavType();
return list;
}
}
- 在模板service层 定义新的方法: 作用就是数据转换树形结构
// xxx-system/.../service/impl/
@Override
public List<OwNavTypeTree> getTreeNavType() {
List<OwNavTypeTree> types = owNavigationMapper.getTreeNavType();
//将返回的一个集合数据 转换成 树形结构数据
types = this.parseNavTypeTree(types);
return types;
}
//转换树形结构方法
public List<OwNavTypeTree> parseNavTypeTree(List<OwNavTypeTree> list) {
//1.先创建一个新的集合
List<OwNavTypeTree> result = new ArrayList<>();
//2. 获取第一个节点 如果等于null 就是根节点
for(OwNavTypeTree navType: list) {
if(null == navType.getPid()) {
result.add(navType);
}
}
//3. 递归获取子节点
for(OwNavTypeTree parent : result) {
parent = recurTree(parent, list);
}
return result;
}
//递归方法
public OwNavTypeTree recurTree(OwNavTypeTree parent, List<OwNavTypeTree> list) {
for(OwNavTypeTree navType : list) {
if(parent.getId().equals(navType.getPid())) {
navType = recurTree(navType, list);
parent.getData().add(navType);
}
}
return parent;
}
- 定义新的实体类
// xxx-system/.../domain/
package com.cms2.system.domain;
import com.cms2.common.annotation.Excel;
import com.cms2.common.core.domain.BaseEntity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 导航分类树形结构 实体类
*/
public class OwNavTypeTree extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键id */
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/** 父导航id */
@JsonSerialize(using = ToStringSerializer.class)
private Long pid;
/** 导航名称 */
private String name;
// 当前导航的子分类数据
private List<OwNavTypeTree> childNavTypes;
//给当前分类添加一个空集合
private List<OwNavTypeTree> data = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<OwNavTypeTree> getChildNavTypes() {
if(null == childNavTypes) {
childNavTypes = new ArrayList<>();
}
return childNavTypes;
}
public void setChildNavTypes(List<OwNavTypeTree> childNavTypes) {
this.childNavTypes = childNavTypes;
}
public List<OwNavTypeTree> getData() {
return data;
}
public void setData(List<OwNavTypeTree> data) {
this.data = data;
}
@Override
public String toString() {
return "OwNavTypeTree{" +
"id=" + id +
", pid=" + pid +
", name='" + name + '\'' +
", childNavTypes=" + childNavTypes +
", data=" + data +
'}';
}
}
- 在 mapper 中写入对应的 方法
-
然后再 mapper映射文件写入对应的方法即可
效果:
1615622263(1).png
8. 删除已分配菜单?
https://www.jianshu.com/p/7b70c3569f8a
先把和这个菜单关联的角色删除,或者修改;在把这个角色关联的用户删除或者修改即可