一 文件的上传-commons-fileupload配置
1 服务器中启动FastDFS和Nginx
cd /usr/local/soft/nginx/sbin/nginx
2 文件上传访问流程图
3 ego-manage中加入文件上传的依赖
<!-- 文件上传依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
4 在ego-manage-WebConfiguration中配置全局解释器
@Bean(name = "multipartResolver")//注意事项,上传解释器的对象名必须为这个,固定的
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver resolver=new CommonsMultipartResolver();
resolver.setMaxUploadSize(200000000);//最大文件上传大小 大约200m
resolver.setDefaultEncoding("UTF-8");
return resolver;
}
5 ego-manage新建图片控制器PicController
@RestController
@Slf4j
public class PicController {
@PostMapping("/pic/upload")
public Map<String,Object>update(MultipartFile uploadFile){
log.debug("原始文件名:"+uploadFile.getOriginalFilename());
return null;
}
}
6 ego-manage-webConfiguration中新增“增加商品”路径
registry.addViewController("/item-add").setViewName("item-add");
7 启动项目,配置完成!
二 文件的上传-FastDFS的上传
1 commons加入FastDFS的依赖
<!--FastDFS依赖-->
<dependency>
<groupId>cn.bestwu</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
2 commons-util中增加FastDFS工具类
/**
* FastDFS分布式文件系统操作客户端.
*/
public class FastDFSClient {
// private static final String CONF_FILENAME = Thread.currentThread().getContextClassLoader().getResource("").getPath() + "fdfs_client.conf";
private static final String CONF_FILENAME = "fdfs_client.conf";
private static StorageClient storageClient = null;
/**
* 只加载一次.
*/
static {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
TrackerServer trackerServer = trackerClient.getConnection();
StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
storageClient = new StorageClient(trackerServer, storageServer);
} catch (Exception e) {
e.printStackTrace();}}
/**
* @param inputStream 上传的文件输入流
* @param fileName 上传的文件原始名
* @return
*/
public static String[] uploadFile(InputStream inputStream, String fileName) {
try {
// 文件的元数据
NameValuePair[] meta_list = new NameValuePair[2];
// 第一组元数据,文件的原始名称
meta_list[0] = new NameValuePair("file name", fileName);
// 第二组元数据
meta_list[1] = new NameValuePair("file length", inputStream.available() + "");
// 准备字节数组
byte[] file_buff = null;
if (inputStream != null) {
// 查看文件的长度
int len = inputStream.available();
// 创建对应长度的字节数组
file_buff = new byte[len];
// 将输入流中的字节内容,读到字节数组中。
inputStream.read(file_buff);}
// 上传文件。参数含义:要上传的文件的内容(使用字节数组传递),上传的文件的类型(扩展名),元数据
String[] fileids = storageClient.upload_file(file_buff, getFileExt(fileName), meta_list);
return fileids;
} catch (Exception ex) {
ex.printStackTrace();
return null;}}
/**
* @param file 文件
* @param fileName 文件名
* @return 返回Null则为失败
*/
public static String[] uploadFile(File file, String fileName) {
FileInputStream fis = null;
try {
NameValuePair[] meta_list = null; // new NameValuePair[0];
fis = new FileInputStream(file);
byte[] file_buff = null;
if (fis != null) {
int len = fis.available();
file_buff = new byte[len];
fis.read(file_buff);}
String[] fileids = storageClient.upload_file(file_buff, getFileExt(fileName), meta_list);
return fileids;
} catch (Exception ex) {
return null;
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace(); }}}}
/**
* 根据组名和远程文件名来删除一个文件
* @param groupName 例如 "group1" 如果不指定该值,默认为group1
* @param remoteFileName 例如"M00/00/00/wKgxgk5HbLvfP86RAAAAChd9X1Y736.jpg"
* @return 0为成功,非0为失败,具体为错误代码
*/
public static int deleteFile(String groupName, String remoteFileName) {
try {
int result = storageClient.delete_file(groupName == null ? "group1" : groupName, remoteFileName);
return result;
} catch (Exception ex) {
return 0;
}
}
/**
* 修改一个已经存在的文件
*
* @param oldGroupName 旧的组名
* @param oldFileName 旧的文件名
* @param file 新文件
* @param fileName 新文件名
* @return 返回空则为失败
*/
public static String[] modifyFile(String oldGroupName, String oldFileName, File file, String fileName) {
String[] fileids = null;
try {
// 先上传
fileids = uploadFile(file, fileName);
if (fileids == null) {
return null;
}
// 再删除
int delResult = deleteFile(oldGroupName, oldFileName);
if (delResult != 0) {
return null;
}
} catch (Exception ex) {
return null;
}
return fileids;
}
/**
* 文件下载
*
* @param groupName 卷名
* @param remoteFileName 文件名
* @return 返回一个流
*/
public static InputStream downloadFile(String groupName, String remoteFileName) {
try {
byte[] bytes = storageClient.download_file(groupName, remoteFileName);
InputStream inputStream = new ByteArrayInputStream(bytes);
return inputStream;
} catch (Exception ex) {
return null;
}
}
public static NameValuePair[] getMetaDate(String groupName, String remoteFileName) {
try {
NameValuePair[] nvp = storageClient.get_metadata(groupName, remoteFileName);
return nvp;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* 获取文件后缀名(不带点).
*
* @return 如:"jpg" or "".
*/
private static String getFileExt(String fileName) {
if (StringUtils.isBlank(fileName) || !fileName.contains(".")) {
return "";
} else {
return fileName.substring(fileName.lastIndexOf(".") + 1); // 不带最后的点
}
}
}
3 在commons-resourece中加入配置文件
fdfs_client.conf
4 新建一个vo类UploadResult
专门用来出来文件上传的返回
/**
* 问题:上传返回的参数名是谁决定的
* 答:使用前台的KingEditor控件决定的
*/
@Data
public class UploadResult {
private int error;
private String url;
private String message;
public static UploadResult ok(String url){
UploadResult result=new UploadResult();
result.setError(0);//成功错误码为0
result.setUrl(url);
result.setMessage(null);
return result;
}
public static UploadResult error(String message){
UploadResult result=new UploadResult();
result.setError(1);//失败错误码为1
result.setUrl(null);
result.setMessage(message);
return result;
}
}
5 ego-manage新建接口
public interface PicService {
/**
* 文件上传
* @param file spring MVC上传对象
*/
UploadResult update(MultipartFile file) throws IOException;
}
6 ego-manage接口PicService 实现类
6.1前提
需要一个获取生成图片名或商品id的工具类
/**
* 各种id生成策略
* @version 1.0
*/
public class IDUtils {
/**
* 图片名生成
*/
public static String genImageName() {
//取当前时间的长整形值包含毫秒
long millis = System.currentTimeMillis();
//long millis = System.nanoTime();
//加上三位随机数
Random random = new Random();
int end3 = random.nextInt(999);
//如果不足三位前面补0
String str = millis + String.format("%03d", end3);
return str;
}
/**
* 商品id生成
*/
public static long genItemId() {
//取当前时间的长整形值包含毫秒
long millis = System.currentTimeMillis();
//long millis = System.nanoTime();
//加上两位随机数
Random random = new Random();
int end2 = random.nextInt(99);
//如果不足两位前面补0
String str = millis + String.format("%02d", end2);
long id = new Long(str);
return id;
}
public static void main(String[] args) {
for(int i=0;i< 100;i++)
System.out.println(genItemId());
}
}
6.2编写PicServiceImp
@Service
@Slf4j
public class PicServiceImp implements PicService {
@Value("${ego.upload.base.path}")
private String basePath;
@Override
public UploadResult update(MultipartFile file) throws IOException {
//输入流
//文件名 自定义一个不重复的文件名
String imageName = IDUtils.genImageName();
String originalFilename = file.getOriginalFilename();
String fileName=imageName+originalFilename.substring(originalFilename.lastIndexOf("."));
String[] strings = FastDFSClient.uploadFile(file.getInputStream(), fileName);
log.debug(Arrays.toString(strings));
//构建访问路径格式: http://192.168.56.100/组名/文件名
log.debug("基础路径:"+basePath);
String url=basePath+"/"+strings[0]+"/"+strings[1];
log.debug("图片访问路径:"+url);
return UploadResult.ok(url);
}
}
7 编辑PicController
@RestController
@Slf4j
public class PicController {
@Autowired
private PicService picService;
@PostMapping("/pic/upload")
public UploadResult update(MultipartFile uploadFile){
try {
log.debug("原始文件名:"+uploadFile.getOriginalFilename());
return picService.update(uploadFile);
} catch (IOException e) {
e.printStackTrace();
}
return UploadResult.error("上传失败");
}
}
8 启动项目,上传图片
8.1上传成功
8.2 http访问到
三 类目的选择-异步树的实现
1 导入ItemCat的pojo和mapper
@Data
@TableName("tb_item_cat")
public class ItemCat implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private Long parentId;
private String name;
private Integer status;
private Integer sortOrder;
private Integer isParent;
private Date created;
private Date updated;
}
public interface ItemCatMapper extends BaseMapper<ItemCat> {
}
2 commons新建ItemCatDubboService
public interface ItemCatDubboService {
/**
* 根据父id查询所有子类目
* @param pid 父id
* @return 所有子类目
*/
List<ItemCat> selectByPid(Long pid);
}
3 ItemCatDubboServiceImp实现
@DubboService
public class ItemCatDubboServiceImp implements ItemCatDubboService {
@Autowired
private ItemCatMapper itemCatMapper;
@Override
public List<ItemCat> selectByPid(Long pid) {
QueryWrapper<ItemCat> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id", pid);
wrapper.eq("status", 1);
List<ItemCat> itemCats = itemCatMapper.selectList(wrapper);
return itemCats;
}
}
4 新增异步树的vo实现类EasyUITree
/**
* 树节点
*/
@Data
public class EasyUITree {
private Long id;
private String text;
private String state;
}
4 ego-manage的服务层调用
ItemCatService
public interface ItemCatService {
/**
* 显示树状菜单
*
* @param pid 父id
* @return 所有子菜单
*/
List<EasyUITree> showTree(Long pid) ;
}
ItemCatServiceImp
@Service
public class ItemCatServiceImp implements ItemCatService {
@DubboReference
private ItemCatDubboService itemCatDubboService;
@Override
public List<EasyUITree> showTree(Long pid) {
//第一步 获取返回对象
List<EasyUITree> nodes = new ArrayList<>();
// 第二步 获得数据
List<ItemCat> tbItemCats = itemCatDubboService.selectByPid(pid);
// 第三步 封装数据
for (ItemCat tbItemCat : tbItemCats) {
EasyUITree node = new EasyUITree();
node.setId(tbItemCat.getId());
node.setText(tbItemCat.getName());
//默认情况下,需要折叠,异步树的实现机制
//数据库里有一个is_parent 是父节点,表示该节点是根节点或枝节点,不然为叶节点
//根据分析,叶节点都没有子节点了,所以展开
//根和枝节点 有子节点,所以需要折叠
if (tbItemCat.getIsParent() == 1) {
node.setState("closed");//折叠 EasyUI确定的字符串,表示折叠
} else {
node.setState("open");//打开
}
nodes.add(node);
}
return nodes;
}
}
5 新建ItemCatController
@RestController
@RequestMapping(value = "/item/cat")
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
@PostMapping(value = "/list")
public List<EasyUITree> showTree(@RequestParam(defaultValue = "0")Long id){
return itemCatService.showTree(id);
}
}
6 启动项目 查看类目列表
四 新增商品
前提须知
新增商品时,新增商品的数据其实是insert到tb_item 和 tb_item_desc两张表的
1 导入tb_item_desc表的pojo和mapper
@Data
@TableName("tb_item_desc")
public class ItemDesc implements Serializable {
@TableId(type = IdType.INPUT)
private Long itemId;
private String itemDesc;
private Date created;
private Date updated;
}
public interface ItemDescMapper extends BaseMapper<ItemDesc> {
}
2 ItemDubboService 新增插入方法
/**
* 新增商品
*/
int insert(Item item, ItemDesc itemDesc) throws DaoException;
3 provider- ItemDubboServiceImp实现
@Override
public int insert(Item item, ItemDesc itemDesc) throws DaoException {
//第一步 插入商品表数据
Long itemId = IDUtils.genItemId();
item.setId(itemId);
item.setUpdated(new Date());
item.setCreated(item.getUpdated());
item.setStatus(1);
itemMapper.insert(item);
System.out.println(itemId);
//第二步 插入商品详情
itemDesc.setItemId(itemId);
itemDesc.setUpdated(item.getUpdated());
itemDesc.setCreated(item.getCreated());
itemDescMapper.insert(itemDesc);
return 1;
}
4 manage服务层远程调用
ItemService
/**
* 保存商品信息
*/
EgoResult save(Item item, String tbItemDesc) throws DaoException;
ItemServiceImp
@Override
public EgoResult save(Item item, String tbItemDesc) throws DaoException {
ItemDesc itemDescObject=new ItemDesc();
itemDescObject.setItemDesc(tbItemDesc);
int insert = itemDubboService.insert(item, itemDescObject);
if (insert==1){
return EgoResult.ok();
}
return EgoResult.error("增加商品失败");
}
5 编写ItemController
/**
* 增加商品
*/
@PostMapping("/save")
public EgoResult insert(Item item, String desc){
try {
return itemService.save(item,desc);
} catch (DaoException e) {
e.printStackTrace();
}
return EgoResult.error("增加商品失败");
}
6 启动项目,实现商品新增
数据库可以查询到
五 实现商品的编辑
1 编辑跳转路径
在item-list页面修改编辑跳转的路径为”item-edit”
<div id="itemEditWindow" class="easyui-window" title="编辑商品" data-options="modal:true,closed:true,iconCls:'icon-save',href:'/item-edit'" style="width:80%;height:80%;padding:10px;">
2 WebConfiguration新增编辑路径
registry.addViewController("/item-edit").setViewName("item-edit");
3 新建ItemDescDubboService
public interface ItemDescDubboService {
/**
* 根据商品编号查询商品详细信息
* @param id
* @return
*/
ItemDesc selectById(Long id);
}
4 provider实现ItemDescDubboService
@DubboService
public class ItemDescDubboServiceImp implements ItemDescDubboService {
@Autowired
private ItemDescMapper itemDescMapper;
@Override
public ItemDesc selectById(Long id) {
return itemDescMapper.selectById(id);
}
}
5 manage服务层调用
ItemDescService
public interface ItemDescService {
/**
* 通过编号查询指定商品描述
* @param id
* @return
*/
EgoResult selectById(Long id);
}
ItemDescServiceImp
@Service
public class ItemDescServiceImp implements ItemDescService {
@DubboReference
private ItemDescDubboService itemDescDubboService;
@Override
public EgoResult selectById(Long id) {
ItemDesc itemDesc = itemDescDubboService.selectById(id);
return EgoResult.ok(itemDesc);
}
}
6 在item-list页面修改获取商品详细信息的路径
7 新建ItemDescController
@RestController
@RequestMapping("/item/desc")
public class ItemDescController {
/**
* 根据商品编号显示详细内容
*/
@Autowired
private ItemDescService itemDescService;
@GetMapping("/{id}")
public EgoResult showDesc(@PathVariable Long id){
return itemDescService.selectById(id);
}
}
8 ItemDubboService 商品更新方法
/**
* 商品更新
*/
int update(Item item, ItemDesc itemDesc) throws DaoException;
9 ItemDubboServiceImp实现更新方法
@Override
public int update(Item item, ItemDesc itemDesc) throws DaoException {
//第一步 更新商品表数据
item.setUpdated(new Date());
item.setCreated(item.getUpdated());
itemMapper.updateById(item);
//第二步 插入商品详情
itemDesc.setUpdated(item.getUpdated());
itemDesc.setCreated(item.getCreated());
itemDescMapper.updateById(itemDesc);
return 1;
}
10 manage服务层远程调用
ItemService
/**
* 更新商品信息
*/
EgoResult update(Item item, String itemDesc) throws DaoException;
ItemServiceImp
@Override
public EgoResult update(Item item, String itemDesc) throws DaoException {
ItemDesc tbItemDescObject=new ItemDesc();
tbItemDescObject.setItemId(item.getId());
tbItemDescObject.setItemDesc(itemDesc);
int insert = itemDubboService.update(item, tbItemDescObject);
if (insert==1){
return EgoResult.ok();
}
return EgoResult.error("编辑商品失败");
}
11 在 item-edit页面修改编辑跳转路径
$.post("/item/update",$("#itemeEditForm").serialize(), function(data){
12 编辑ItemController
/**
* 编辑商品
*/
@PostMapping("/update")//更新使用POST方法
public EgoResult update(Item item,String desc) {
try {
return itemService.update(item,desc);
} catch (DaoException e) {
e.printStackTrace();
}
return EgoResult.error("编辑失败");
}
13 启动项目 编辑成功