1. SpringBoot整合jsp進行頁面訪問出現找不到file文件
問題:css
前提是:跳轉代碼沒有問題,以下圖java
解決1:配置springMVC視圖解析器
解決2:來源於Idea的自身bug
2. ego項目總結
第一天
(1)SpringSecurity結合ego項目進行操做步驟
1. 搭建ego_commons
2. 編寫ego_api
在ego_api中建立com.ego.dubbo.service.ManagerDubboService實現查詢用戶功能nginx
public interface ManagerDubboService {
/** * 根據用戶名查詢用戶信息 * @param username 用戶名 * @return 用戶信息 */ Manager selectManagerByUsername(String username); }web |
3. 編寫ego_provide
在ego_provide中建立com.ego.dubbo.service.impl.ManagerDubboServiceImpl 實現類spring
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; } }apache |
修改啓動類,添加MapperScanjson
@SpringBootApplication @EnableDubbo @MapperScan("com.ego.mapper") public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class,args); } }api |
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);} |