day15【前台】項目釋出
1、OSS
1.1、開通OSS服務
- 進入控制台,選擇【對象存儲OSS】
- 立即開通
- 同意協定
- 開通完成後,前往控制台建立
Bucket
1.2、建立Bucket
- 建立
Bucket
-
名稱Bucket
- 設定區域為附近區域
- 設定為低頻通路存儲,适用于較少通路的服務
- 不開通【版本控制】
- 讀寫權限設定為公共讀:讀取無需登入,寫入需要登入
1.3、頁面上傳檔案
- 建立目錄用于存儲檔案
- 建立多級目錄
- 選擇上傳檔案
- 上傳本地圖檔至阿裡雲
OSS
- 圖檔的位址:
域名+圖檔路徑Bucket
1.4、建立子使用者AccessKey
- 一般我們不使用主賬戶(登入賬戶)來調用 API 接口,因為主賬戶的權限太大,一旦 key secret 洩露,就玩完。。。
- 一般建立子賬戶來調用 OSS API 接口,點選使用者頭像,選擇 AccessKey管理
- 選擇開始使用子使用者 AccessKey
- 設計登入名稱和顯示名稱,選擇程式設計通路(自己編寫的程式調用或 PicGo 等第三方程式調用)
-
貌似僅此一次機會可以檢視,趕緊儲存下來Key Secret
1.5、子使用者AccessKey授權
- 給建立的子使用者添權重限
- 添加 OSS 服務:AliyunOSSFullAccess ,FullAccess 表示可讀可寫
1.6、project-consumer環境
1.6.1、引入依賴
- 在
工程中引入所需的依賴project-consumer
<dependencies>
<!-- api工程 -->
<dependency>
<groupId>com.atguigu.crowd</groupId>
<artifactId>atcrowdfunding17-member-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- yml配置檔案智能提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- web标配 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 單元測試 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- thymeleaf模闆引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入springboot&redis整合場景 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入springboot&springsession整合場景 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
</dependencies>
1.6.2、建立主啟動類
//啟用Feign用戶端功能
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class CrowdMainClass {
public static void main(String[] args) {
SpringApplication.run(CrowdMainClass.class, args);
}
}
1.6.3、準備OSSProperties類
- 建立
配置類OSSProperties
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class OSSProperties {
private String endPoint;
private String bucketName;
private String accessKeyId;
private String accessKeySecret;
private String bucketDomain;
}
1.6.4、建立yml配置檔案
- 微服務端口号
- 微服務名稱
-
模闆引擎Thymeleaf
-
相關配置SpringSession
- 指定
注冊中心的位址Eureka
- 阿裡雲
基本配置OSS
server:
port: 5000
spring:
application:
name: atguigu-crowd-project
thymeleaf:
prefix: classpath:/templates/
suffix: .html
redis:
host: 192.168.152.129
session:
store-type: redis
eureka:
client:
service-url:
defaultZone: http://localhost:1000/eureka
aliyun:
oss:
access-key-id: <填入你的access-key-id>
access-key-secret: <填入你的access-key-secret>
bucket-domain: <填入你的bucket-domain>
bucket-name: <填入你的bucket-name>
end-point: <填入你的end-point>
-
和bucket-domain
去阿裡雲控制台複制,end-point
就是bucket-name
(當初建立heygo
時取的名字)Bucket
1.7、上傳檔案工具方法
1.7.1、引入依賴
- 在
工程引入阿裡雲util
服務所需的依賴OSS
<!-- OSS用戶端SDK -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.5.0</version>
</dependency>
1.7.2、建立工具方法
- 在工具類中添加如下方法
/**
* 專門負責上傳檔案到OSS伺服器的工具方法
* @param endpoint OSS參數
* @param accessKeyId OSS參數
* @param accessKeySecret OSS參數
* @param inputStream 要上傳的檔案的輸入流
* @param bucketName OSS參數
* @param bucketDomain OSS參數
* @param originalName 要上傳的檔案的原始檔案名
* @return 包含上傳結果以及上傳的檔案在OSS上的通路路徑
*/
public static ResultEntity<String> uploadFileToOss(
String endpoint,
String accessKeyId,
String accessKeySecret,
InputStream inputStream,
String bucketName,
String bucketDomain,
String originalName) {
// 建立OSSClient執行個體。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 生成上傳檔案的目錄
String folderName = new SimpleDateFormat("yyyyMMdd").format(new Date());
// 生成上傳檔案在OSS伺服器上儲存時的檔案名
// 原始檔案名:beautfulgirl.jpg
// 生成檔案名:wer234234efwer235346457dfswet346235.jpg
// 使用UUID生成檔案主體名稱
String fileMainName = UUID.randomUUID().toString().replace("-", "");
// 從原始檔案名中擷取檔案擴充名
String extensionName = originalName.substring(originalName.lastIndexOf("."));
// 使用目錄、檔案主體名稱、檔案擴充名稱拼接得到對象名稱
String objectName = folderName + "/" + fileMainName + extensionName;
try {
// 調用OSS用戶端對象的方法上傳檔案并擷取響應結果資料
PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, inputStream);
// 從響應結果中擷取具體響應消息
ResponseMessage responseMessage = putObjectResult.getResponse();
// 根據響應狀态碼判斷請求是否成功
if(responseMessage == null) {
// 拼接通路剛剛上傳的檔案的路徑
String ossFileAccessPath = bucketDomain + "/" + objectName;
// 目前方法傳回成功
return ResultEntity.successWithData(ossFileAccessPath);
} else {
// 擷取響應狀态碼
int statusCode = responseMessage.getStatusCode();
// 如果請求沒有成功,擷取錯誤消息
String errorMessage = responseMessage.getErrorResponseAsString();
// 目前方法傳回失敗
return ResultEntity.failed("目前響應狀态碼="+statusCode+" 錯誤消息="+errorMessage);
}
} catch (Exception e) {
e.printStackTrace();
// 目前方法傳回失敗
return ResultEntity.failed(e.getMessage());
} finally {
if(ossClient != null) {
// 關閉OSSClient。
ossClient.shutdown();
}
}
}
1.8、測試
1.8.1、建立測試類
@RunWith(SpringRunner.class)
@SpringBootTest
public class OSSTest {
@Autowired
private OSSProperties oSSProperties;
@Test
public void testOSS() throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream("SpongeBob.jpg");
ResultEntity<String> resultEntity = CrowdUtil.uploadFileToOss(
oSSProperties.getEndPoint(),
oSSProperties.getAccessKeyId(),
oSSProperties.getAccessKeySecret(),
inputStream,
oSSProperties.getBucketName(),
oSSProperties.getBucketDomain(),
"SpongeBob.jpg");
System.out.println(resultEntity.getResult());
}
}
- 圖檔放置路徑:工程根目錄下
1.8.2、測試結果
- 控制台列印
SUCCESS
-
上傳圖檔成功OSS
2、跳轉到發起項目頁面
2.1、整體思路
2.2、解決Zuul相關問題
2.2.1、序列化
-
存儲對象至SpringSession
中,要求該類必須是可序列化的,否則會抛異常Redis
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberLoginVO implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String email;
}
2.2.2、session中資料莫名消失
1、問題描述
- 明明 在登陸成功之後,将
對象存入了MemberLoginVO
,卻取不出來,提示session
為session
null
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "session.loginMember.username" (template: "member-center" - line 69, col 121)
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'username' cannot be found on null
2、問題分析
-
所屬域名為auth-consumer
,http://localhost:4000
所屬域名為zuul
,他他倆屬于不同的域名, 浏覽器工作時不會使用相同的http://localhost:80
,自然Cookie
就不一樣(不共享)咯session
3、解決方法
- 以後重定向的位址都按照通過
通路的方式寫位址Zuul
@RequestMapping("/auth/member/do/login")
public String login(
@RequestParam("loginacct") String loginacct,
@RequestParam("userpswd") String userpswd,
ModelMap modelMap,
HttpSession session) {
// 1.調用遠端接口根據登入賬号查詢MemberPO對象
ResultEntity<MemberPO> resultEntity =
mySQLRemoteService.getMemberPOByLoginAcctRemote(loginacct);
if(ResultEntity.FAILED.equals(resultEntity.getResult())) {
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, resultEntity.getMessage());
return "member-login";
}
MemberPO memberPO = resultEntity.getData();
if(memberPO == null) {
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_LOGIN_FAILED);
return "member-login";
}
// 2.比較密碼
String userpswdDataBase = memberPO.getUserpswd();
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
boolean matcheResult = passwordEncoder.matches(userpswd, userpswdDataBase);
if(!matcheResult) {
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_LOGIN_FAILED);
return "member-login";
}
// 3.建立MemberLoginVO對象存入Session域
MemberLoginVO memberLoginVO = new MemberLoginVO(memberPO.getId(), memberPO.getUsername(), memberPO.getEmail());
session.setAttribute(CrowdConstant.ATTR_NAME_LOGIN_MEMBER, memberLoginVO);
// 使用重定向避免重新整理浏覽器導緻重新執行注冊流程
// 以後重定向的位址都按照通過 Zuul通路的方式寫位址
return "redirect:http://www.crowd.com/auth/member/to/center/page";
}
// 使用重定向避免重新整理浏覽器導緻重新執行注冊流程
// 以後重定向的位址都按照通過 Zuul通路的方式寫位址
return "redirect:http://www.crowd.com/auth/member/to/center/page";
- 這裡隻是以一個
方法作為示例,在工程中所有重定向的前面,都加上域名:Handler
http://www.crowd.com
2.2.3、頁面跳轉位址
1、前置域名問題
- 需要注意: 前面要寫上域名(如果沒有配置域名寫
一樣), 確定通過localhost
通路具體功能。Zuul
- 因為必須通過
通路具體微服務才能夠保持Zuul
, 進而保持Cookie
一緻Session
2、Cookie之Domain
-
保持一緻,Domain
才能保持一緻,Cookie
才能保持一緻session
3、舉例
- 【退出系統】按鈕的超連結
- 退出成功後,頁面重定向至
http://www.crowd.com
2.2.4、ClassNotFoundException
1、問題描述
-
異常ClassNotFoundException
Caused by: java.lang.ClassNotFoundException: com.atguigu.crowd.entity.vo.MemberLoginVO
2、引入依賴
- 在
中會從ZuulFilter
中讀取Redis
對象的資訊,并進行反序列化,是以我們需要在MemberLoginVO
工程中引入zuul
工程的依賴entity
<!-- entity實體類工程 -->
<dependency>
<groupId>com.atguigu.crowd</groupId>
<artifactId>atcrowdfunding09-member-entity</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2.2.5、測試
- 正常通路~~~并且域名是
www.crowd.com
2.3、我的衆籌
2.3.1、修改超連結
- 修改【我的衆籌】超連結
<div class="list-group-item " style="cursor:pointer;">
<a th:href="@{/member/my/crowd}">我的衆籌</a><span class="badge"><i class="glyphicon glyphicon-chevron-right"></i></span>
</div>
2.3.2、添加view-controller
- 通過
進行跳轉,view-controller
位址對應着/member/my/crowd
頁面templates/member-crowd.html
@Configuration
public class CrowdWebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 添加view-controller
// 浏覽器通路的位址
// 目标視圖的名稱,将來拼接“prefix: classpath:/templates/”、“suffix: .html”前字尾
registry.addViewController("/auth/member/to/reg/page").setViewName("member-reg");
registry.addViewController("/auth/member/to/login/page").setViewName("member-login");
registry.addViewController("/auth/member/to/center/page").setViewName("member-center");
registry.addViewController("/member/my/crowd").setViewName("member-crowd");
}
}
2.3.3、衆籌頁面
- 添加衆籌頁面,并添加使用者資訊的回顯
2.3.4、測試
- 點選【我的衆籌】,正常跳轉
3、發起項目
3.1、整體思路
3.2、建立資料庫表
3.2.1、分類表
- 分類表用于存儲項目的分類資訊
CREATE TABLE t_type (
id INT (11) NOT NULL AUTO_INCREMENT,
NAME VARCHAR (255) COMMENT '分類名稱',
remark VARCHAR (255) COMMENT '分類介紹',
PRIMARY KEY (id)
)
3.2.2、項目分類中間表
- 項目分類中間表用于存儲項目與分類之間的對應關系
CREATE TABLE t_project_type (
id INT NOT NULL AUTO_INCREMENT,
projectid INT (11),
typeid INT (11),
PRIMARY KEY (id)
) ;
3.2.3、标簽表
- 标簽表用于存儲項目的标簽資訊
create table t_tag (
id int (11) not null auto_increment,
pid int (11),
name varchar (255),
primary key (id)
) ;
3.2.4、項目标簽中間表
- 項目标簽中間表用于存儲項目與标簽之間的對應關系
CREATE TABLE t_project_tag (
id INT (11) NOT NULL AUTO_INCREMENT,
projectid INT (11),
tagid INT (11),
PRIMARY KEY (id)
) ;
3.2.5、項目表
- 項目表用于存儲項目的詳細資訊
CREATE TABLE t_project (
id INT (11) NOT NULL AUTO_INCREMENT,
project_name VARCHAR (255) COMMENT '項目名稱',
project_description VARCHAR (255) COMMENT '項目描述',
money BIGINT (11) COMMENT '籌集金額',
DAY INT (11) COMMENT '籌集天數',
STATUS INT (4) COMMENT '0-即将開始, 1-衆籌中, 2-衆籌成功, 3-衆籌失敗',
deploydate VARCHAR (10) COMMENT '項目發起時間',
supportmoney BIGINT (11) COMMENT '已籌集到的金額',
supporter INT (11) COMMENT '支援人數',
COMPLETION INT (3) COMMENT '百分比完成度',
memberid INT (11) COMMENT '發起人的會員 id',
createdate VARCHAR (19) COMMENT '項目建立時間',
follower INT (11) COMMENT '關注人數',
header_picture_path VARCHAR (255) COMMENT '頭圖路徑',
PRIMARY KEY (id)
) ;
3.2.6、項目詳情圖檔表
- 由于使用者可以上傳多張項目詳情圖檔,是以我們單獨建個表存儲項目詳情圖檔
CREATE TABLE t_project_item_pic (
id INT (11) NOT NULL AUTO_INCREMENT,
projectid INT (11),
item_pic_path VARCHAR (255),
PRIMARY KEY (id)
) ;
3.2.7、項目發起人資訊表
- 項目發起人資訊表用于存儲項目發起人的詳細資訊
create table t_member_launch_info (
id int (11) not null auto_increment,
memberid int (11) comment '會員 id',
description_simple varchar (255) comment '簡單介紹',
description_detail varchar (255) comment '詳細介紹',
phone_num varchar (255) comment '聯系電話',
service_num varchar (255) comment '客服電話',
primary key (id)
) ;
3.2.8、回報資訊表
- 回報資訊表用于存儲衆籌的回報資訊
CREATE TABLE t_return (
id INT (11) NOT NULL AUTO_INCREMENT,
projectid INT (11),
TYPE INT (4) COMMENT '0 - 實物回報, 1 虛拟物品回報',
supportmoney INT (11) COMMENT '支援金額',
content VARCHAR (255) COMMENT '回報内容',
COUNT INT (11) COMMENT '回報産品限額, 0為不限回報數量',
signalpurchase INT (11) COMMENT '是否設定單筆限購',
purchase INT (11) COMMENT '具體限購數量',
freight INT (11) COMMENT '運費, 0為包郵',
invoice INT (4) COMMENT '0 - 不開發票, 1 - 開發票',
returndate INT (11) COMMENT '項目結束後多少天向支援者發送回報',
describ_pic_path VARCHAR (255) COMMENT '說明圖檔路徑',
PRIMARY KEY (id)
) ;
3.2.9、發起人确認資訊表
- 發起人确認資訊表用于存儲發起人的詳細資訊
CREATE TABLE t_member_confirm_info (
id INT (11) NOT NULL AUTO_INCREMENT,
memberid INT (11) COMMENT '會員 id',
paynum VARCHAR (200) COMMENT '易付寶企業賬号',
cardnum VARCHAR (200) COMMENT '法人身份證号',
PRIMARY KEY (id)
)
3.3、逆向工程
3.3.1、逆向工程配置檔案
- 注意:不生成中間表對應的實體類
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- mybatis-generator:generate -->
<context id="atguiguTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的注釋 true:是;false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--資料庫連接配接的資訊:驅動類、連接配接位址、使用者名、密碼 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/project_crowd"
userId="root"
password="root">
</jdbcConnection>
<!-- 預設false,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer,為 true時把JDBC DECIMAL
和 NUMERIC 類型解析為java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成Entity類的路徑 -->
<javaModelGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.entity.po">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
<!-- 從資料庫傳回的值被清理前後的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:XxxMapper.xml映射檔案生成的路徑 -->
<sqlMapGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:Mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 資料庫表名字和我們的entity類對應的映射指定 -->
<table tableName="t_type" domainObjectName="TypePO" />
<table tableName="t_tag" domainObjectName="TagPO" />
<table tableName="t_project" domainObjectName="ProjectPO" />
<table tableName="t_project_item_pic" domainObjectName="ProjectItemPicPO" />
<table tableName="t_member_launch_info" domainObjectName="MemberLaunchInfoPO" />
<table tableName="t_return" domainObjectName="ReturnPO" />
<table tableName="t_member_confirm_info" domainObjectName="MemberConfirmInfoPO" />
</context>
</generatorConfiguration>
<javaModelGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.entity.po">
...
</javaModelGenerator>
<!-- 資料庫表名字和我們的entity類對應的映射指定 -->
<table tableName="t_type" domainObjectName="TypePO" />
<table tableName="t_tag" domainObjectName="TagPO" />
<table tableName="t_project" domainObjectName="ProjectPO" />
<table tableName="t_project_item_pic" domainObjectName="ProjectItemPicPO" />
<table tableName="t_member_launch_info" domainObjectName="MemberLaunchInfoPO" />
<table tableName="t_return" domainObjectName="ReturnPO" />
<table tableName="t_member_confirm_info" domainObjectName="MemberConfirmInfoPO" />
3.3.2、執行逆向工程
-
指令:Maven Build
mybatis-generator:generate
3.3.3、資源歸位
1、實體類
2、Mapper接口
3、Mapper.xml映射檔案
3.4、建立元件
3.4.1、ProjectHandler
3.4.2、ProjectService
3.5、建立VO類
-
:項目詳細資訊ProjectVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProjectVO implements Serializable {
private static final long serialVersionUID = 1L;
// 分類id集合
private List<Integer> typeIdList;
// 标簽id集合
private List<Integer> tagIdList;
// 項目名稱
private String projectName;
// 項目描述
private String projectDescription;
// 計劃籌集的金額
private Integer money;
// 籌集資金的天數
private Integer day;
// 建立項目的日期
private String createdate;
// 頭圖的路徑
private String headerPicturePath;
// 詳情圖檔的路徑
private List<String> detailPicturePathList;
// 發起人資訊
private MemberLauchInfoVO memberLauchInfoVO;
// 回報資訊集合
private List<ReturnVO> returnVOList;
// 發起人确認資訊
private MemberConfirmInfoVO memberConfirmInfoVO;
}
-
:項目發起人資訊MemberLauchInfoVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberLauchInfoVO implements Serializable {
private static final long serialVersionUID = 1L;
// 簡單介紹
private String descriptionSimple;
// 詳細介紹
private String descriptionDetail;
// 聯系電話
private String phoneNum;
// 客服電話
private String serviceNum;
}
-
:回報資訊ReturnVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReturnVO implements Serializable {
private static final long serialVersionUID = 1L;
// 回報類型:0 - 實物回報, 1 虛拟物品回報
private Integer type;
// 支援金額
private Integer supportmoney;
// 回報内容介紹
private String content;
// 總回報數量,0為不限制
private Integer count;
// 是否限制單筆購買數量,0表示不限購,1表示限購
private Integer signalpurchase;
// 如果單筆限購,那麼具體的限購數量
private Integer purchase;
// 運費,“0”為包郵
private Integer freight;
// 是否開發票,0 - 不開發票, 1 - 開發票
private Integer invoice;
// 衆籌結束後返還回報物品天數
private Integer returndate;
// 說明圖檔路徑
private String describPicPath;
}
-
:發起人确認資訊MemberConfirmInfoVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberConfirmInfoVO implements Serializable {
private static final long serialVersionUID = 1L;
// 易付寶賬号
private String paynum;
// 法人身份證号
private String cardnum;
}
3.6、zuul路由規則
- 在
中配置zuul
的路由規則:atguigu-crowd-project
/project/**
- 注意:
- 如果一個請求需要經過
,請求路徑必須帶上zuul
部分/project
- 如果一個請求無需經過
,隻在zuul
微服務中做轉發(比如配置atguigu-crowd-project
等),那麼請求路徑就不能帶view-controller
部分/project
- 如果一個請求需要經過
zuul:
ignored-services: "*"
sensitive-headers: "*" # 在Zuul向其他微服務重定向時保持原本頭資訊(請求頭、響應頭)
routes:
crowd-portal:
service-id: atguigu-crowd-auth
path: /** # 這裡一定要使用兩個“*”号,不然“/”路徑後面的多層路徑将無法通路
crowd-project:
service-id: atguigu-crowd-project
path: /project/** # 這裡一定要使用兩個“*”号,不然“/”路徑後面的多層路徑将無法通路
3.7、跳轉至發起項目頁面
3.7.1、點選發起衆籌
- 修改【發起衆籌】按鈕的跳轉位址
-
表示浏覽器的跳轉位址window.location.href = "http://www.crowd.com/project/agree/protocol/page";
- 一定要經過
網關再進行跳轉,否則會出現zuul
不一緻的問題session
-
<li class=" pull-right">
<script type="text/javascript">
$(function(){
$("#launchCrowdBtn").click(function(){
window.location.href = "http://www.crowd.com/project/agree/protocol/page";
});
});
</script>
<button id="launchCrowdBtn" type="button"
class="btn btn-warning">發起衆籌</button></li>
3.7.2、配置view-controller
- 在
中配置project-consumer
,view-controller
- 因為
是在view-controller
内部定義的,是以這裡是一個不經過project-consumer
通路的位址,是以這個路徑前面不加路由規則中定義的字首:Zuul
/project
@Configuration
public class CrowdWebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// view-controller是在project-consumer内部定義的,是以這裡是一個不經過Zuul通路的位址,是以這個路徑前面不加路由規則中定義的字首:“/project”
registry.addViewController("/agree/protocol/page").setViewName("project-agree");
registry.addViewController("/launch/project/page").setViewName("project-launch");
}
}
3.7.3、使用者協定頁面
- 在
工程中,建立使用者協定頁面、發起項目頁面project-consumer
3.7.4、測試
- 點選【發起衆籌】跳轉至【使用者協定】頁面
- 再點選【閱讀并同意協定】,則可以跳轉至發起項目頁面
3.8、常量定義
public class CrowdConstant {
public static final String MESSAGE_LOGIN_FAILED = "抱歉!賬号密碼錯誤!請重新輸入!";
public static final String MESSAGE_LOGIN_ACCT_ALREADY_IN_USE = "抱歉!這個賬号已經被使用了!";
public static final String MESSAGE_ACCESS_FORBIDEN = "請登入以後再通路!";
public static final String MESSAGE_STRING_INVALIDATE = "字元串不合法!請不要傳入空字元串!";
public static final String MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE = "系統錯誤:登入賬号不唯一!";
public static final String MESSAGE_ACCESS_DENIED = "抱歉!您不能通路這個資源!";
public static final String MESSAGE_CODE_NOT_EXISTS = "驗證碼已過期!請檢查手機号是否正确或重新發送!";
public static final String MESSAGE_CODE_INVALID = "驗證碼不正确!";
public static final String MESSAGE_HEADER_PIC_UPLOAD_FAILED = "頭圖上傳失敗!";
public static final String MESSAGE_HEADER_PIC_EMPTY = "頭圖不可為空!";
public static final String MESSAGE_DETAIL_PIC_EMPTY = "詳情圖檔不可為空!";
public static final String MESSAGE_DETAIL_PIC_UPLOAD_FAILED = "詳情圖檔上傳失敗!";
public static final String MESSAGE_TEMPLE_PROJECT_MISSING = "臨時存儲的Project對象丢失!";
public static final String ATTR_NAME_EXCEPTION = "exception";
public static final String ATTR_NAME_LOGIN_ADMIN = "loginAdmin";
public static final String ATTR_NAME_LOGIN_MEMBER = "loginMember";
public static final String ATTR_NAME_PAGE_INFO = "pageInfo";
public static final String ATTR_NAME_MESSAGE = "message";
public static final String ATTR_NAME_TEMPLE_PROJECT = "tempProject";
public static final String REDIS_CODE_PREFIX = "REDIS_CODE_PREFIX_";
}
3.9、送出項目詳情資訊
3.9.1、目标
- 将如下表單資訊封裝到
對象中,儲存至ProjectVO
域中,以便後續收集完成,儲存至資料庫中session
3.9.2、前端表單送出代碼
- 标簽資訊需要單獨采集,最後以隐藏域的形式追加在表單資料後面
// 點選下一步按鈕送出表單
$("#submitBtn").click(function(){
// 将表單中标簽id的值組成的數組轉換成表單内的隐藏域
for(var i = 0; i < tagIdList.length; i++) {
var tagId = tagIdList[i];
var hiddenInputHTML = "<input type='hidden' name='tagIdList' value='"+tagId+"' />";
$("#projectForm").append(hiddenInputHTML);
}
// 送出表單
$("#projectForm").submit();
});
3.9.3、Handler方法
- 建立
,用于接收表單送出的資料ProjectConsumerHandler
- 接收表單送出的
對象ProjectVO
- 接收上傳的頭圖,上傳至
,并設定圖檔的網絡路徑OSS
- 接收項目的詳情圖檔,上傳至
,并設定圖檔的網絡路徑OSS
- 将
對象存入ProjectVO
域中,并轉發至回報頁面session
- 接收表單送出的
@Controller
public class ProjectConsumerHandler {
@Autowired
private OSSProperties ossProperties;
@RequestMapping("/create/project/information")
public String saveProjectBasicInfo(
// 接收除了上傳圖檔之外的其他普通資料
ProjectVO projectVO,
// 接收上傳的頭圖
MultipartFile headerPicture,
// 接收上傳的詳情圖檔
List<MultipartFile> detailPictureList,
// 用來将收集了一部分資料的ProjectVO對象存入Session域
HttpSession session,
// 用來在目前操作失敗後傳回上一個表單頁面時攜帶提示消息
ModelMap modelMap
) throws IOException {
// 一、完成頭圖上傳
// 1.擷取目前headerPicture對象是否為空
boolean headerPictureIsEmpty = headerPicture.isEmpty();
if(headerPictureIsEmpty) {
// 2.如果沒有上傳頭圖則傳回到表單頁面并顯示錯誤消息
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_HEADER_PIC_EMPTY);
return "project-launch";
}
// 3.如果使用者确實上傳了有内容的檔案,則執行上傳
ResultEntity<String> uploadHeaderPicResultEntity = CrowdUtil.uploadFileToOss(
ossProperties.getEndPoint(),
ossProperties.getAccessKeyId(),
ossProperties.getAccessKeySecret(),
headerPicture.getInputStream(),
ossProperties.getBucketName(),
ossProperties.getBucketDomain(),
headerPicture.getOriginalFilename());
String result = uploadHeaderPicResultEntity.getResult();
// 4.判斷頭圖是否上傳成功
if(ResultEntity.SUCCESS.equals(result)) {
// 5.如果成功則從傳回的資料中擷取圖檔通路路徑
String headerPicturePath = uploadHeaderPicResultEntity.getData();
// 6.存入ProjectVO對象中
projectVO.setHeaderPicturePath(headerPicturePath);
} else {
// 7.如果上傳失敗則傳回到表單頁面并顯示錯誤消息
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_HEADER_PIC_UPLOAD_FAILED);
return "project-launch";
}
// 二、上傳詳情圖檔
// 1.建立一個用來存放詳情圖檔路徑的集合
List<String> detailPicturePathList = new ArrayList<String>();
// 2.檢查detailPictureList是否有效
if(detailPictureList == null || detailPictureList.size() == 0) {
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_DETAIL_PIC_EMPTY);
return "project-launch";
}
// 3.周遊detailPictureList集合
for (MultipartFile detailPicture : detailPictureList) {
// 4.目前detailPicture是否為空
if(detailPicture.isEmpty()) {
// 5.檢測到詳情圖檔中單個檔案為空也是回去顯示錯誤消息
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_DETAIL_PIC_EMPTY);
return "project-launch";
}
// 6.執行上傳
ResultEntity<String> detailUploadResultEntity = CrowdUtil.uploadFileToOss(
ossProperties.getEndPoint(),
ossProperties.getAccessKeyId(),
ossProperties.getAccessKeySecret(),
detailPicture.getInputStream(),
ossProperties.getBucketName(),
ossProperties.getBucketDomain(),
detailPicture.getOriginalFilename());
// 7.檢查上傳結果
String detailUploadResult = detailUploadResultEntity.getResult();
if(ResultEntity.SUCCESS.equals(detailUploadResult)) {
String detailPicturePath = detailUploadResultEntity.getData();
// 8.收集剛剛上傳的圖檔的通路路徑
detailPicturePathList.add(detailPicturePath);
} else {
// 9.如果上傳失敗則傳回到表單頁面并顯示錯誤消息
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_DETAIL_PIC_UPLOAD_FAILED);
return "project-launch";
}
}
// 10.将存放了詳情圖檔通路路徑的集合存入ProjectVO中
projectVO.setDetailPicturePathList(detailPicturePathList);
// 三、後續操作
// 1.将ProjectVO對象存入Session域
session.setAttribute(CrowdConstant.ATTR_NAME_TEMPLE_PROJECT, projectVO);
// 2.以完整的通路路徑前往下一個收集回報資訊的頁面
return "redirect:http://www.crowd.com/project/return/info/page";
}
}
3.9.4、添加view-controller
@Configuration
public class CrowdWebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// view-controller是在project-consumer内部定義的,是以這裡是一個不經過Zuul通路的位址,是以這個路徑前面不加路由規則中定義的字首:“/project”
registry.addViewController("/agree/protocol/page").setViewName("project-agree");
registry.addViewController("/launch/project/page").setViewName("project-launch");
registry.addViewController("/return/info/page").setViewName("project-return");
}
}
3.10、添加回報頁面
3.11、測試
- 圖檔能上傳至阿裡與
OSS
-
中的Redis
session
4、送出回報資訊
4.1、整體思路
4.2、Ajax上傳圖檔
4.2.1、前端Ajax請求
- 以
形式送出圖檔,并通過響應資訊擷取圖檔的網絡位置Ajax
-
:在頁面位址中需要帶上"url":"[[@{/project/create/upload/return/picture.json}]]"
網關的路由規則,即域名+微服務路徑zuul
project
// 在檔案上傳框的值改變事件響應函數中預覽并上傳圖檔
$("[name=returnPicture]").change(function(event){
var file = event.target.files[0];
var url = window.url || window.webkitURL;
var path = url.createObjectURL(file);
$(this).next().next().next().next().attr("src",path).show();
// 将上傳的檔案封裝到FormData對象中
var formData = new FormData();
formData.append("returnPicture", file);
// 發送Ajax請求上傳檔案
$.ajax({
"url":"[[@{/project/create/upload/return/picture.json}]]",
"type":"post",
"data":formData,
"contentType":false,
"processData":false,
"dataType":"json",
"success":function(response){
var result = response.result;
if(result == "SUCCESS") {
alert("上傳成功!");
// 如果上傳成功,則從響應體資料中擷取圖檔的通路路徑
returnObj.describPicPath = response.data;
}
if(result == "FAILED") {
alert(response.message);
}
},
"error":function(response){
alert(response.status + " " + response.statusText);
}
});
});
4.2.2、後端Handler代碼
- 将圖檔上傳至
,并傳回上傳的結果OSS
// JavaScript代碼:formData.append("returnPicture", file);
// returnPicture是請求參數的名字
// file是請求參數的值,也就是要上傳的檔案
@ResponseBody
@RequestMapping("/create/upload/return/picture.json")
public ResultEntity<String> uploadReturnPicture(
// 接收使用者上傳的檔案
@RequestParam("returnPicture") MultipartFile returnPicture) throws IOException {
// 1.執行檔案上傳
ResultEntity<String> uploadReturnPicResultEntity = CrowdUtil.uploadFileToOss(
ossProperties.getEndPoint(),
ossProperties.getAccessKeyId(),
ossProperties.getAccessKeySecret(),
returnPicture.getInputStream(),
ossProperties.getBucketName(),
ossProperties.getBucketDomain(),
returnPicture.getOriginalFilename());
// 2.傳回上傳的結果
return uploadReturnPicResultEntity;
}
4.3、Ajax送出表單
4.3.1、前端Ajax請求
- 收集表單項,送出
請求Ajax
// 聲明序号儲存表格中資料的序号
var order = 0;
// 點選确定按鈕,綁定單擊響應函數
$("#okBtn").click(function(){
// 1.收集表單資料
returnObj.type = $("[name=type]:checked").val();
returnObj.supportmoney = $("[name=supportmoney]").val();
returnObj.content = $("[name=content]").val();
returnObj.count = $("[name=count]").val();
returnObj.signalpurchase = $("[name=signalpurchase]:checked").val();
returnObj.purchase = $("[name=purchase]").val();
returnObj.freight = $("[name=freight]").val();
returnObj.invoice = $("[name=invoice]:checked").val();
returnObj.returndate = $("[name=returndate]").val();
// 2.發送Ajax請求
$.ajax({
"url" : "[[@{/project/create/save/return.json}]]",
"type": "post",
"dataType": "json",
"data": returnObj,
"success": function(response) {
var result = response.result;
if(result == "SUCCESS") {
alert("這一條儲存成功!");
// 使用returnObj填充表格
var orderTd = "<td>"+(++order)+"</td>";
var supportmoneyTd = "<td>"+returnObj.supportmoney+"</td>";
var countTd = "<td>"+returnObj.count+"</td>";
var signalpurchaseTd = "<td>"+(returnObj.signalpurchase == 0?"不限購":("限購"+returnObj.purchase))+"</td>";
var contentTd = "<td>"+returnObj.content+"</td>";
var returndateTd = "<td>"+returnObj.returndate+"天以後返還</td>";
var freightTd = "<td>"+(returnObj.freight==0?"包郵":returnObj.freight)+"</td>";
var operationTd = "<td><button type='button' class='btn btn-primary btn-xs'><i class=' glyphicon glyphicon-pencil'></i></button> <button type='button' class='btn btn-danger btn-xs'><i class=' glyphicon glyphicon-remove'></i></button></td>";
var trHTML = "<tr>"+orderTd+supportmoneyTd+countTd+signalpurchaseTd+contentTd+returndateTd+freightTd+operationTd+"</tr>";
$("#returnTableBody").append(trHTML);
$("#returnPictureImage").hide();
}
if(result == "FAILED") {
alert("這一條儲存失敗!");
}
// 後續操作
// 僅僅調用click()函數而不傳入回調函數表示點選一下這個按鈕
$("#resetBtn").click();
// 将表單部分div隐藏
$(".returnFormDiv").hide();
}
});
});
4.3.2、後端Handler代碼
- 取出
中的Redis
對象,用該對象接收表單發送的ProjectVO
對象,更新ReturnVO
中的session
對象ProjectVO
@ResponseBody
@RequestMapping("/create/save/return.json")
public ResultEntity<String> saveReturn(ReturnVO returnVO, HttpSession session) {
try {
// 1.從session域中讀取之前緩存的ProjectVO對象
ProjectVO projectVO = (ProjectVO) session.getAttribute(CrowdConstant.ATTR_NAME_TEMPLE_PROJECT);
// 2.判斷projectVO是否為null
if(projectVO == null) {
return ResultEntity.failed(CrowdConstant.MESSAGE_TEMPLE_PROJECT_MISSING);
}
// 3.從projectVO對象中擷取存儲回報資訊的集合
List<ReturnVO> returnVOList = projectVO.getReturnVOList();
// 4.判斷returnVOList集合是否有效
if(returnVOList == null || returnVOList.size() == 0) {
// 5.建立集合對象對returnVOList進行初始化
returnVOList = new ArrayList<>();
// 6.為了讓以後能夠正常使用這個集合,設定到projectVO對象中
projectVO.setReturnVOList(returnVOList);
}
// 7.将收集了表單資料的returnVO對象存入集合
returnVOList.add(returnVO);
// 8.把資料有變化的ProjectVO對象重新存入Session域,以確定新的資料最終能夠存入Redis
session.setAttribute(CrowdConstant.ATTR_NAME_TEMPLE_PROJECT, projectVO);
// 9.所有操作成功完成傳回成功
return ResultEntity.successWithoutData();
} catch (Exception e) {
e.printStackTrace();
return ResultEntity.failed(e.getMessage());
}
}
4.4、測試
- 回報資訊送出成功
- 阿裡雲
上傳圖檔成功OSS
5、送出确認資訊
5.1、建立頁面
-
:确認資訊頁面project-confirm.html
-
:成功頁面project-success.html
5.2、修改【下一步】超連結
- 修改回報資訊頁面【下一步】按鈕的超連結,點選【下一步】按鈕,跳轉至成功頁面
5.3、添加view-controller
@Configuration
public class CrowdWebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// view-controller是在project-consumer内部定義的,是以這裡是一個不經過Zuul通路的位址,是以這個路徑前面不加路由規則中定義的字首:“/project”
registry.addViewController("/agree/protocol/page").setViewName("project-agree");
registry.addViewController("/launch/project/page").setViewName("project-launch");
registry.addViewController("/return/info/page").setViewName("project-return");
registry.addViewController("/create/confirm/page").setViewName("project-confirm");
registry.addViewController("/create/success").setViewName("project-success");
}
}
registry.addViewController("/create/confirm/page").setViewName("project-confirm");
registry.addViewController("/create/success").setViewName("project-success");
5.4、确認資訊表單
-
送出位址與action
方法對應Handler
- 表單标簽項的
屬性與name
實體類屬性名對應VO
<form id="confirmFomr" th:action="@{/project/create/confirm}" method="post" role="form">
<div class="form-group">
<label for="exampleInputEmail1">易付寶企業賬号:</label><input type="email" name="paynum" class="form-control" id="exampleInputEmail1" />
</div>
<div class="form-group">
<label for="exampleInputPassword1">法人身份證号:</label><input type="password" name="cardnum" class="form-control" id="exampleInputPassword1" />
</div>
</form>
5.5、送出按鈕
- 點選【送出】按鈕送出表單
<script type="text/javascript">
$(function(){
$("#submitBtn").click(function(){
$("#confirmFomr").submit();
});
});
</script>
<button type="button" id="submitBtn" class="btn btn-warning btn-lg">送出</button>
5.6、Handler代碼
- 從
域中取出session
對象ProjectVO
- 更新
對象的确認資訊ProjectVO
- 将
對象送出至ProjectVO
進行儲存mysql-provider
- 儲存成功則删除
域中的session
對象,并重定向至成功頁面ProjectVO
@Autowired
private MySQLRemoteService mySQLRemoteService;
@RequestMapping("/create/confirm")
public String saveConfirm(ModelMap modelMap, HttpSession session, MemberConfirmInfoVO memberConfirmInfoVO) {
// 1.從Session域讀取之前臨時存儲的ProjectVO對象
ProjectVO projectVO = (ProjectVO) session.getAttribute(CrowdConstant.ATTR_NAME_TEMPLE_PROJECT);
// 2.如果projectVO為null
if(projectVO == null) {
throw new RuntimeException(CrowdConstant.MESSAGE_TEMPLE_PROJECT_MISSING);
}
// 3.将确認資訊資料設定到projectVO對象中
projectVO.setMemberConfirmInfoVO(memberConfirmInfoVO);
// 4.從Session域讀取目前登入的使用者
MemberLoginVO memberLoginVO = (MemberLoginVO) session.getAttribute(CrowdConstant.ATTR_NAME_LOGIN_MEMBER);
Integer memberId = memberLoginVO.getId();
// 5.調用遠端方法儲存projectVO對象
ResultEntity<String> saveResultEntity = mySQLRemoteService.saveProjectVORemote(projectVO, memberId);
// 6.判斷遠端的儲存操作是否成功
String result = saveResultEntity.getResult();
if(ResultEntity.FAILED.equals(result)) {
modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, saveResultEntity.getMessage());
return "project-confirm";
}
// 7.将臨時的ProjectVO對象從Session域移除
session.removeAttribute(CrowdConstant.ATTR_NAME_TEMPLE_PROJECT);
// 8.如果遠端儲存成功則跳轉到最終完成頁面
return "redirect:http://www.crowd.com/project/create/success";
}
5.7、api遠端調用接口聲明
- 在
遠端調用接口中聲明上述方法MySQLRemoteService
@FeignClient("atguigu-crowd-mysql")
public interface MySQLRemoteService {
@RequestMapping("/get/memberpo/by/login/acct/remote")
ResultEntity<MemberPO> getMemberPOByLoginAcctRemote(@RequestParam("loginacct") String loginacct);
@RequestMapping("/save/member/remote")
public ResultEntity<String> saveMember(@RequestBody MemberPO memberPO);
@RequestMapping("/save/project/vo/remote")
ResultEntity<String> saveProjectVORemote(@RequestBody ProjectVO projectVO, @RequestParam("memberId") Integer memberId);
}
6、執行儲存
6.1、Handler代碼
-
中調用本地Handler
方法完成項目資訊的儲存Service
@RestController
public class ProjectProviderHandler {
@Autowired
private ProjectService projectService;
@RequestMapping("/save/project/vo/remote")
public ResultEntity<String> saveProjectVORemote(
@RequestBody ProjectVO projectVO,
@RequestParam("memberId") Integer memberId) {
try {
// 調用“本地”Service執行儲存
projectService.saveProject(projectVO, memberId);
return ResultEntity.successWithoutData();
} catch (Exception e) {
e.printStackTrace();
return ResultEntity.failed(e.getMessage());
}
}
}
6.2、Service代碼
- 分為如下步驟:
- 儲存
對象ProjectPO
- 儲存項目分類資訊
- 儲存項目标簽資訊
- 儲存項目發起人資訊
- 儲存項目回報資訊
- 儲存項目确認資訊
- 儲存
@Transactional(readOnly = true)
@Service
public class ProjectServiceImpl implements ProjectService {
@Autowired
private ReturnPOMapper returnPOMapper;
@Autowired
private MemberConfirmInfoPOMapper memberConfirmInfoPOMapper;
@Autowired
private MemberLaunchInfoPOMapper memberLaunchInfoPOMapper;
@Autowired
private ProjectPOMapper projectPOMapper;
@Autowired
private ProjectItemPicPOMapper projectItemPicPOMapper;
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
@Override
public void saveProject(ProjectVO projectVO, Integer memberId) {
// 一、儲存ProjectPO對象
// 1.建立空的ProjectPO對象
ProjectPO projectPO = new ProjectPO();
// 2.把projectVO中的屬性複制到projectPO中
BeanUtils.copyProperties(projectVO, projectPO);
// 修複bug:把memberId設定到projectPO中
projectPO.setMemberid(memberId);
// 修複bug:生成建立時間存入
String createdate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
projectPO.setCreatedate(createdate);
// 修複bug:status設定成0,表示即将開始
projectPO.setStatus(0);
// 3.儲存projectPO
// 為了能夠擷取到projectPO儲存後的自增主鍵,需要到ProjectPOMapper.xml檔案中進行相關設定
// <insert id="insertSelective" useGeneratedKeys="true" keyProperty="id" ……
projectPOMapper.insertSelective(projectPO);
// 4.從projectPO對象這裡擷取自增主鍵
Integer projectId = projectPO.getId();
// 二、儲存項目、分類的關聯關系資訊
// 1.從ProjectVO對象中擷取typeIdList
List<Integer> typeIdList = projectVO.getTypeIdList();
projectPOMapper.insertTypeRelationship(typeIdList, projectId);
// 三、儲存項目、标簽的關聯關系資訊
List<Integer> tagIdList = projectVO.getTagIdList();
projectPOMapper.insertTagRelationship(tagIdList, projectId);
// 四、儲存項目中詳情圖檔路徑資訊
List<String> detailPicturePathList = projectVO.getDetailPicturePathList();
projectItemPicPOMapper.insertPathList(projectId, detailPicturePathList);
// 五、儲存項目發起人資訊
MemberLauchInfoVO memberLauchInfoVO = projectVO.getMemberLauchInfoVO();
MemberLaunchInfoPO memberLaunchInfoPO = new MemberLaunchInfoPO();
BeanUtils.copyProperties(memberLauchInfoVO, memberLaunchInfoPO);
memberLaunchInfoPO.setMemberid(memberId);
memberLaunchInfoPOMapper.insert(memberLaunchInfoPO);
// 六、儲存項目回報資訊
List<ReturnVO> returnVOList = projectVO.getReturnVOList();
List<ReturnPO> returnPOList = new ArrayList<>();
for (ReturnVO returnVO : returnVOList) {
ReturnPO returnPO = new ReturnPO();
BeanUtils.copyProperties(returnVO, returnPO);
returnPOList.add(returnPO);
}
returnPOMapper.insertReturnPOBatch(returnPOList, projectId);
// 七、儲存項目确認資訊
MemberConfirmInfoVO memberConfirmInfoVO = projectVO.getMemberConfirmInfoVO();
MemberConfirmInfoPO memberConfirmInfoPO = new MemberConfirmInfoPO();
BeanUtils.copyProperties(memberConfirmInfoVO, memberConfirmInfoPO);
memberConfirmInfoPO.setMemberid(memberId);
memberConfirmInfoPOMapper.insert(memberConfirmInfoPO);
}
}
6.3、擷取自增主鍵
- 設定插入資料時,擷取插入資料的自增主鍵
-
:擷取自增主鍵useGeneratedKeys="true"
-
:keyProperty="id"
類中主鍵屬性名為PO
id
-
<insert id="insertSelective" useGeneratedKeys="true" keyProperty="id" parameterType="com.atguigu.crowd.entity.po.ProjectPO" >
insert into t_project
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null" >
id,
</if>
<if test="projectName != null" >
project_name,
</if>
<if test="projectDescription != null" >
project_description,
</if>
<if test="money != null" >
money,
</if>
<if test="day != null" >
day,
</if>
<if test="status != null" >
status,
</if>
<if test="deploydate != null" >
deploydate,
</if>
<if test="supportmoney != null" >
supportmoney,
</if>
<if test="supporter != null" >
supporter,
</if>
<if test="completion != null" >
completion,
</if>
<if test="memberid != null" >
memberid,
</if>
<if test="createdate != null" >
createdate,
</if>
<if test="follower != null" >
follower,
</if>
<if test="headerPicturePath != null" >
header_picture_path,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null" >
#{id,jdbcType=INTEGER},
</if>
<if test="projectName != null" >
#{projectName,jdbcType=VARCHAR},
</if>
<if test="projectDescription != null" >
#{projectDescription,jdbcType=VARCHAR},
</if>
<if test="money != null" >
#{money,jdbcType=BIGINT},
</if>
<if test="day != null" >
#{day,jdbcType=INTEGER},
</if>
<if test="status != null" >
#{status,jdbcType=INTEGER},
</if>
<if test="deploydate != null" >
#{deploydate,jdbcType=VARCHAR},
</if>
<if test="supportmoney != null" >
#{supportmoney,jdbcType=BIGINT},
</if>
<if test="supporter != null" >
#{supporter,jdbcType=INTEGER},
</if>
<if test="completion != null" >
#{completion,jdbcType=INTEGER},
</if>
<if test="memberid != null" >
#{memberid,jdbcType=INTEGER},
</if>
<if test="createdate != null" >
#{createdate,jdbcType=VARCHAR},
</if>
<if test="follower != null" >
#{follower,jdbcType=INTEGER},
</if>
<if test="headerPicturePath != null" >
#{headerPicturePath,jdbcType=VARCHAR},
</if>
</trim>
</insert>
6.4、儲存項目分類資訊
6.4.1、項目分類表
- 存儲項目與分類資訊之間的關聯關系
6.4.2、Mapper接口
void insertTypeRelationship(
@Param("typeIdList") List<Integer> typeIdList,
@Param("projectId") Integer projectId);
6.4.3、Mapper映射檔案
<!--
void insertTypeRelationship(
@Param("typeIdList") List<Integer> typeIdList,
@Param("projectId") Integer projectId);
-->
<insert id="insertTypeRelationship">
insert into t_project_type(`projectid`,`typeid`) values
<foreach collection="typeIdList" item="typeId" separator=",">(#{projectId},#{typeId})</foreach>
</insert>
6.5、儲存項目标簽資訊
6.5.1、項目标簽表
- 存儲項目與标簽資訊之間的關聯關系
6.5.2、Mapper接口
void insertTagRelationship(
@Param("tagIdList") List<Integer> tagIdList,
@Param("projectId") Integer projectId);
6.5.3、Mapper映射檔案
<!--
void insertTagRelationship(
@Param("tagIdList") List<Integer> tagIdList,
@Param("projectId") Integer projectId);
-->
<insert id="insertTagRelationship">
insert into `t_project_tag`(`projectid`,`tagid`) values
<foreach collection="tagIdList" item="tagId" separator=",">(#{projectId},#{tagId})</foreach>
</insert>
6.6、儲存項目詳情圖檔
6.6.1、項目詳情圖檔表
- 存儲項目詳情圖檔的網絡路徑
6.6.2、Mapper接口
void insertPathList(
@Param("projectId") Integer projectId,
@Param("detailPicturePathList") List<String> detailPicturePathList);
6.6.3、Mapper映射檔案
<!--
void insertPathList(
@Param("projectId") Integer projectId,
@Param("detailPicturePathList") List<String> detailPicturePathList);
-->
<insert id="insertPathList">
insert into t_project_item_pic (projectid, item_pic_path)
values
<foreach collection="detailPicturePathList" item="detailPath" separator=",">(#{projectId},#{detailPath})</foreach>
</insert>
6.7、儲存項目回報資訊
6.7.1、項目回報表
- 存儲項目的回報資訊
6.7.2、Mapper接口
void insertReturnPOBatch(
@Param("returnPOList") List<ReturnPO> returnPOList,
@Param("projectId") Integer projectId);
6.7.3、Mapper映射檔案
<!--
void insertReturnPOBatch(
@Param("returnPOList") List<ReturnPO> returnPOList,
@Param("projectId") Integer projectId);
-->
<insert id="insertReturnPOBatch">
insert into t_return (
projectid,
type,
supportmoney,
content,
count,
signalpurchase,
purchase,
freight,
invoice,
returndate,
describ_pic_path
)
values
<foreach collection="returnPOList" item="returnPO" separator=",">
(
#{projectId},
#{returnPO.type},
#{returnPO.supportmoney},
#{returnPO.content},
#{returnPO.count},
#{returnPO.signalpurchase},
#{returnPO.purchase},
#{returnPO.freight},
#{returnPO.invoice},
#{returnPO.returndate},
#{returnPO.describPicPath}
)
</foreach>
</insert>
6.8、測試
- 送出資料成功~
-
:t_project
詳細資訊Project
-
:項目與分類的關聯關系t_project_type
-
:項目與标簽的關聯關系t_project_tag
-
:項目詳情圖檔的路徑t_project_item_pic
-
:發起人資訊t_member_launch_info
-
:回報資訊t_return
-
:确認資訊t_member_confirm_info
-
上傳圖檔成功OSS
6.9、遇到的問題
- 可以看到,
字段的值并沒有儲存成功,我們需要将money
字段的類型從money
修改為Long
Integer
-
逆向生成時,将Mybatis
類的ProjectPO
字段的類型設定為money
,而我們自己寫的Long
類的ProjectVO
字段的類型為money
Integer
- 用
拷貝屬性值時,貌似會拷貝失敗???反正請求參數中的BeanUtils.copyProperties
字段值能正常注入money