ego商城项目学习总结+出现问题及解决

1. SpringBoot整合jsp进行页面访问出现找不到file文件

问题:

 

前提是:跳转代码没有问题,如下图

 

解决1:配置springMVC视图解析器

 

解决2:来源于Idea的自身bug

 

2. ego项目总结

第一天

(1)SpringSecurity结合ego项目进行操作步骤

1. 搭建ego_commons

2. 编写ego_api

ego_api中创建com.ego.dubbo.service.ManagerDubboService实现查询用户功能

public interface ManagerDubboService {

    /**
     * 根据用户名查询用户信息
     * @param username 用户名
     * @return 用户信息
     */
    Manager selectManagerByUsername(String username);
}

3. 编写ego_provide

ego_provide中创建com.ego.dubbo.service.impl.ManagerDubboServiceImpl 实现类

ps:注意(provider中)此处的@Service注解导入的是apache

@Service
public class ManagerDubboServiceImpl implements ManagerDubboService {

    @Autowired
    private ManagerMapper managerMapper;

    @Override
    public Manager selectManagerByUsername(String username) {
        ManagerExample example = new ManagerExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<Manager> managers = managerMapper.selectByExample(example);
        if(managers!=null && managers.size()>0){
            return managers.get(0);
        }
        return null;
    }
}

修改启动类,添加MapperScan

@SpringBootApplication
@EnableDubbo
@MapperScan("com.ego.mapper")
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

 

 

4. 编写ego_manage

创建com.ego.config.SecurityConfig

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder getPwdEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginProcessingUrl("/login")
                .successForwardUrl("/loginSuccess")
                .loginPage("/");
        http.authorizeRequests()
                // 放行静态资源
                .antMatchers("/","/css/**","/js/**").permitAll()
                .anyRequest().authenticated();

        http.csrf().disable();
    }
}

创建com.ego.controller.PageController,添加跳转成功后的控制

/**
 * 登录成功后跳转的控制器
 */
@RequestMapping("/loginSuccess")
@ResponseBody
public EgoResult loginSuccess(){
    return EgoResult.ok();
}

 

 

创建com.ego.service.impl.LoginServiceImpl,实现自定义登录逻辑

// Consumer的注解是Spring的
@Service
public class LoginServiceImpl implements UserDetailsService {

    // 此注解用apache的
    @Reference
    private ManagerDubboService managerDubboService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Manager manager = managerDubboService.selectManagerByUsername(s);
        if(manager == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        return new User(s,manager.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("不涉及权限"));
    }
}

 

 

第二天

(1)事务管理部分(事务需要放到provider中进行处理)

eg.批量修改商品状态

@Override
// 监测异常,当有异常时会进行事务回滚,声明式事务注解
@Transactional
public int updateStatusByIds(long[] ids, byte status) throws DaoException{
    int index = 0;
    for (long id : ids) {
        TbItem tbItem = new TbItem();
        tbItem.setId(id);
        tbItem.setStatus(status);
        // 保证批量修改时间相同
        tbItem.setUpdated(new Date());
        index += tbItemMapper.updateByPrimaryKeySelective(tbItem);
    }
    // 如何判断是否批量修改成功?
    // 根据索引数 = ids[] 数组的长度
    if (index == ids.length){
        return 1;
    }
    // 如果失败,需要事务回滚(1.抛出自定义异常2.方法抛出异常3.添加注解Transaction,监听异常从而做出回滚操作)
    throw new DaoException("修改失败");
}

 

事务管理三步:1.抛出自定义异常2.方法抛出异常3.添加注解Transaction,监听异常从而做出回滚操作

 

ps:倘若抛出的自定义异常(DaoException)不是继承RuntimeException而是继承Exception,则此时的事务注解为:@Transaction(rollbackFor = Exception.class)

 

第三天

(1)安装Fastdfs,并且适配Nginx

按照网上步骤进行即可

(2)通过KindEditor上传图片,上传至fastdfs的存储器中

1. 搭建Fastdfs服务器,实现上传功能

首先在ego_commons添加fastdfs依赖,其次添加FastDFSClient工具类

<dependencies>
    <dependency>
        <groupId>cn.bestwu</groupId>
        <artifactId>fastdfs-client-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

FastDFSClient工具类:

package com.ego.commons.utils;

import org.apache.commons.lang3.StringUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import java.io.*;

/**
 * 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); // 不带最后的点
        }
    }
}

ego_manage中添加PicService及实现类

功能:实现上传二进制文件(图片)

思路:1.manage中的返回值为页面需要的信息,因此需要查看KindEditor文档,可知其为json格式数据且key值不同--》采用Map集合存储

  2.nginxHostcommons中定义application-commons.yml文件,通过SpringMVC视图解析器来在manage中激活,如下图。此步骤为软编码

 

在此manage项目引用的时候需采用键值对的方式

package com.ego.service;

import org.springframework.web.multipart.MultipartFile;

import java.util.Map;

public interface PicService {
    /**
     * 上传二进制文件(图片)
     * @param file
     * @return
     */
    Map<String,Object> upload(MultipartFile file);

}

package com.ego.service.impl;

import com.ego.commons.utils.FastDFSClient;
import com.ego.service.PicService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Service
public class PicServiceImpl implements PicService {

    @Value("${ego.fastdfs.nginx}")
    private String nginxHost;
    @Override
    public Map<String, Object> upload(MultipartFile file) {
        Map<String,Object> map = new HashMap<>();
        try {
            String[] results = FastDFSClient.uploadFile(file.getInputStream(), file.getOriginalFilename());
            map.put("error",0);
            // 测试环境和上线环境不一致的情况:通过软编码解决
            map.put("url",nginxHost+results[0]+"/"+results[1]);
            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }
        map.put("error",1);
        map.put("message","错误信息");
        return map;
    }
}

ego_manage中添加PicController控制器

package com.ego.controller;

import com.ego.service.PicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.util.Map;

@Controller
public class PicController {

    @Autowired
    private PicService picService;

    @RequestMapping("/pic/upload")
    @ResponseBody
    public Map<String,Object> update(MultipartFile uploadFile){
        return picService.upload(uploadFile);
    }
}

(3)根据EasyUITree添加选择类目(页面需求)

按照页面所要获取到的EasyUITree创建类TbItemCat

ego_api中添加TbItemCatDubboService

package com.ego.dubbo.service;

import com.ego.pojo.TbItemCat;

import java.util.List;

public interface TbItemCatDubboService {
    /**
     * 根据父id查询类目信息
     * @param pid
     * @return
     */
    public List<TbItemCat> selectByPid(Long pid);
}

ego_provider中添加TbItemCatDubboServiceImpl实现类

package com.ego.dubbo.service.impl;

import com.ego.dubbo.service.TbItemCatDubboService;
import com.ego.dubbo.service.TbItemDubboService;
import com.ego.mapper.TbItemCatMapper;
import com.ego.pojo.TbItemCat;
import com.ego.pojo.TbItemCatExample;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Service
public class TbItemCatDubboServiceImpl implements TbItemCatDubboService {
    @Autowired
    private TbItemCatMapper tbItemCatMapper;
    @Override
    public List<TbItemCat> selectByPid(Long pid) {
        TbItemCatExample example = new TbItemCatExample();
        example.createCriteria().andParentIdEqualTo(pid);
        return tbItemCatMapper.selectByExample(example);
    }
}

ego_manage中添加TbItemCatService及实现类

思路:将TbItemCat类型的数据放到EasyUITree类型中,需要清楚EasyUITree结构

package com.ego.service;

import com.ego.commons.pojo.EasyUITree;

import java.util.List;

public interface TbItemCatService {
    List<EasyUITree> showTree(Long pid);
}

package com.ego.service.impl;

import com.ego.commons.pojo.EasyUITree;
import com.ego.dubbo.service.TbItemCatDubboService;
import com.ego.pojo.TbItemCat;
import com.ego.service.TbItemCatService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class TbItemCatServiceImpl implements TbItemCatService {
    @Reference
    private TbItemCatDubboService tbItemCatDubboService;
    @Override
    public List<EasyUITree> showTree(Long pid) {
        List<EasyUITree> list = new ArrayList<>();
        List<TbItemCat> tbItemCats = tbItemCatDubboService.selectByPid(pid);
        for (TbItemCat tbItemCat:tbItemCats) {
            EasyUITree easyUITree = new EasyUITree();
            easyUITree.setId(tbItemCat.getId());
            easyUITree.setText(tbItemCat.getName());
            easyUITree.setState(tbItemCat.getIsParent()?"closed":"open");
            list.add(easyUITree);
        }
        return list;
    }
}

ego_manage中添加TbItemCatController

开始在数据库表中规定初始id0,需通过@RequestParam(defaultValue = "0")声明

package com.ego.controller;

import com.ego.commons.pojo.EasyUITree;
import com.ego.service.TbItemCatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;

@Controller
public class TbItemCatController {
    @Autowired
    private TbItemCatService tbItemCatService;
    @RequestMapping("/item/cat/list")
    @ResponseBody
    public List<EasyUITree> showTree(@RequestParam(defaultValue = "0") Long id){
        return tbItemCatService.showTree(id);
    }
}

(4)功能:获取(编辑商品信息中的商品描述tbItemDesc

思路:两个表查询(TbItemTbItemDesc)——》考虑事务,根据商品id获取到商品描述

思路为按部就班(ego_api中声明接口——》provider做底层调用Mapper实现数据供给——》manage做业务需求,页面需要哪种类型数据就给哪种数据类型)

(5)功能:提交更新的商品信息

流程演示:

ego_api

int update(TbItem tbItem,TbItemDesc tbItemDesc) throws DaoException;

provider

@Override
@Transactional
public int update(TbItem tbItem, TbItemDesc tbItemDesc) throws DaoException{
    try {
        int index1 = tbItemMapper.updateByPrimaryKeySelective(tbItem);
        if(index1==1){
            int index2 = tbItemDescMapper.updateByPrimaryKeySelective(tbItemDesc);
            if(index2==1){
                return 1;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    throw new DaoException("更新失败");
}

manage

/**
 * 更新商品信息
 * @param tbItem
 * @param desc
 * @return
 */
EgoResult update(TbItem tbItem,String desc);

@Override
public EgoResult update(TbItem tbItem, String desc) {
    Date date = new Date();
    tbItem.setUpdated(date);

    TbItemDesc tbItemDesc = new TbItemDesc();
    tbItemDesc.setItemId(tbItem.getId());
    tbItemDesc.setItemDesc(desc);
    tbItemDesc.setCreated(tbItem.getCreated());
    tbItemDesc.setUpdated(date);

    try {
        int index = tbItemDubboService.update(tbItem, tbItemDesc);
        if(index==1){
            return EgoResult.ok();
        }
    } catch (DaoException e) {
        e.printStackTrace();
    }
    return EgoResult.error();
}

controller

@RequestMapping("/rest/item/update")
@ResponseBody
public EgoResult update(TbItem tbItem,String desc){
    return tbItemService.update(tbItem,desc);
}

原文地址:https://www.cnblogs.com/happy-prince/p/13531512.html