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.nginxHost在commons中定义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
开始在数据库表中规定初始id为0,需通过@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)
思路:两个表查询(TbItem和TbItemDesc)——》考虑事务,根据商品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); }
|