zoukankan      html  css  js  c++  java
  • 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);
    }

  • 相关阅读:
    C#连接MySQL
    国双面试题
    Redis入门安装配置
    vs2013密钥
    单例模式
    用R画韦恩图
    Snipaste截图
    秩和检验
    用R包中heatmap画热图
    OTU(operational taxonomic units),即操作分类单元
  • 原文地址:https://www.cnblogs.com/happy-prince/p/13531512.html
Copyright © 2011-2022 走看看