尚籌網08環境搭建
阿新 • • 發佈:2020-07-25
前端整體結構
服務呼叫
會員系統總目標
- 搭建環境
- 會員登陸註冊
- 發起眾籌專案
- 展示眾籌專案
- 支援眾籌專案
- 訂單
- 支付
會員系統架構
架構圖
需要建立的工程
parent過程配置pom.xml
匯入座標
<!-- 配置在父工程中要管理的依賴 --> <dependencyManagement> <dependencies> <!-- 匯入 SpringCloud 需要使用的依賴資訊 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR2</version> <type>pom</type> <!-- import 依賴範圍表示將 spring-cloud-dependencies 包中的依賴資訊匯入 --> <scope>import</scope> </dependency> <!-- 匯入 SpringBoot 需要使用的依賴資訊 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> </dependencies> </dependencyManagement>
搭建環境約定
埠號
eureka工程
匯入座標
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>
配置檔案
server:
port: 1000
spring:
application:
name: adom-crowd-eureka
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
主啟動類
@EnableEurekaServer @SpringBootApplication public class CrowdApplication { public static void main(String[] args) { SpringApplication.run(CrowdApplication.class,args); } }
entity工程
建立包
lombok原理
相關注解
@Data:每一個欄位都加入getxxx()、setxxx()方法
@NoargsConstructor:無參構造器
@AllArgsConstructor:全部欄位都包括的構造器
@EqualsAndHashCode:equals和hashCode方法
@Getter
類:所有欄位都加入getXxx()方法
欄位:當前欄位加入getXxx()方法
@Setter
類:所有欄位都加入setXxx()方法
欄位:當前欄位加入setXxx()方法
MySQL工程基礎環境
目標
抽取整個專案中所有針對資料庫的操作.
建立資料庫表
DROP TABLE IF EXISTS `t_member`; CREATE TABLE `t_member` ( `id` int(11) NOT NULL AUTO_INCREMENT, `login_acct` varchar(255) NOT NULL, `user_pswd` char(200) NOT NULL, `user_name` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `auth_status` int(4) DEFAULT NULL COMMENT '實名認證狀態0-未實名認證,1-實名認證申請中,2-已實名認證', `user_type` int(4) DEFAULT NULL COMMENT '0-個人,1-企業', `real_name` varchar(255) DEFAULT NULL, `card_num` varchar(255) DEFAULT NULL, `acct_type` int(4) DEFAULT NULL COMMENT '0-企業,1-個體,2-個人,3-政府', PRIMARY KEY (`id`), UNIQUE KEY `login_acct` (`login_acct`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1;
實體
Mapper
匯入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!----> <dependency> <groupId>com.adom</groupId> <artifactId>member-entity</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.adom</groupId> <artifactId>util</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies>
配置檔案
server:
port: 2000
spring:
application:
name: adom-crowd-mysql
datasource:
name: mydb
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/campusfunding?serverTimezone=UTC
username: root
password: 11111111
driver-class-name: com.mysql.cj.jdbc.Driver
eureka:
client:
service-url:
defaultZone: http://localhost:1000/eureka
mybatis:
mapper-locations: classpath*:/mybatis/mapper/*Mapper.xml
# config-location: classpath:mybatis/mybatis-config.xml
logging:
level:
com.adom.crowd.mapper: debug
com.adom.crowd.test: debug
啟動類
@EnableDiscoveryClient @SpringBootApplication @MapperScan("com.adom.crowd.mapper") public class CrowdApplication { public static void main(String[] args) { SpringApplication.run(CrowdApplication.class, args); } }
MYSQL工程API
API依賴
建立介面
@FeignClient("adom-crowd-mysql") public interface MySQLRemoteService { @RequestMapping("/get/memberpo/by/login/acct/remote") ResultEntity<MemberPO> getMemberPOByLoginAcctRemote(@RequestParam("loginacct") String loginacct); }
MySQL工程
controller程式碼
@RestController public class MemberProviderController { @Autowired private MemberService memberService; public ResultEntity<MemberPO> getMemberPOByLoginAcctReemote(@RequestParam("loginacct") String loginacct){ //1、呼叫本地service完成查詢 MemberPO memberPO = memberService.getMemberPOByLoginAcct(loginacct); //2、如果沒有拋異常,那麼就返回成功的結果 return ResultEntity.sucessWithData(memberPO); } }
service程式碼
public MemberPO getMemberPOByLoginAcct(String loginacct) { //1、建立Example物件 MemberPOExample memberPOExample = new MemberPOExample(); //2、建立Criteria物件 MemberPOExample.Criteria criteria = memberPOExample.createCriteria(); //3、封裝查詢條件 criteria.andLoginAcctEqualTo(loginacct); //4、執行查詢 List<MemberPO> memberPOS = memberPOMapper.selectByExample(memberPOExample); //5、獲取結果 return memberPOS.get(0); }
目標
抽取專案中所有訪問Redis的操作
依賴
<dependencies> <!-- 整合 Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 測試 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 對外暴露服務 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 作為客戶端訪問 Eureka 註冊中心 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- 為了能夠使用實體類 --> <dependency> <groupId>com.adom</groupId> <artifactId>member-entity</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <!-- 為了能夠使用工具類 --> <dependency> <groupId>com.adom</groupId> <artifactId>util</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies>
配置檔案
server:
port: 3000
spring:
application:
name: adom-crowd-redis
redis:
host: localhost
eureka:
client:
service-url:
defaultZone: http://localhost:1000/eureka
啟動類
@SpringBootApplication public class CrowdApplication { public static void main(String[] args) { SpringApplication.run(CrowdApplication.class,args); } }
Redis工程API
API工程介面
@FeignClient("com-adom-redis") public interface RedisRemoteService { @RequestMapping("/set/redis/key/value/remote") ResultEntity<String> setRedisKeyValueRemote( @RequestParam("key") String key, @RequestParam("value") String value); @RequestMapping("/set/redis/key/value/remote/with/timeout") ResultEntity<String> setRedisKeyValueRemoteWithTimeout( @RequestParam("key") String key, @RequestParam("value") String value, @RequestParam("time") long time, @RequestParam("timeUnix") TimeUnit timeUnit); @RequestMapping("/get/redis/string/value/by/key") ResultEntity<String> getRedisStringValueByKeyRemote(@RequestParam("key") String key); @RequestMapping("/remove/redis/key/remote") ResultEntity<String> removeRedisKeyRemote(@RequestParam("key") String key); }
controller程式碼
使用StringRedisTemplate元件,操作Redis
@RestController public class RedisController { @Autowired private StringRedisTemplate redisTemplate; ResultEntity<String> setRedisKeyValueRemote( @RequestParam("key") String key, @RequestParam("value") String value ) { try { ValueOperations<String, String> operations = redisTemplate.opsForValue(); operations.set(key, value); return ResultEntity.successWithoutData(); } catch (Exception e) { e.printStackTrace(); return ResultEntity.failed(e.getMessage()); } } @RequestMapping("/get/redis/string/value/by/key") ResultEntity<String> getRedisStringValueByKeyRemote(@RequestParam("key") String key) { try { ValueOperations<String, String> operations = redisTemplate.opsForValue(); String value = operations.get(key); return ResultEntity.sucessWithData(value); } catch (Exception e) { e.printStackTrace(); return ResultEntity.failed(e.getMessage()); } } ResultEntity<String> removeRedisKeyRemote(@RequestParam("key") String key) { try { redisTemplate.delete(key); return ResultEntity.successWithoutData(); } catch (Exception e) { e.printStackTrace(); return ResultEntity.failed(e.getMessage()); } } }
認證工程顯示首頁
匯入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.adom</groupId> <artifactId>member-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
配置檔案
server:
port: 4000
spring:
application:
name: adom-crowd-auth
thymeleaf:
prefix: classpath:/templates/
suffix: .html
eureka:
client:
service-url:
defaultZone: http://localhost:1000/eureka
主啟動類
@EnableDiscoveryClient @SpringBootApplication public class CrowdApplication { public static void main(String[] args) { SpringApplication.run(CrowdApplication.class, args); } }
顯示首頁的controller
@Controller public class PortalController { @RequestMapping("/") public String showPortalPage(){ return "portal"; } }
加入靜態資源
Portal.html
<!DOCTYPE html> <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <base th:href="@{/}"> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="css/font-awesome.min.css"> <link rel="stylesheet" href="css/carousel.css"> <style> h3 { font-weight: bold; } #footer { padding: 15px 0; background: #fff; border-top: 1px solid #ddd; text-align: center; } #topcontrol { color: #fff; z-index: 99; width: 30px; height: 30px; font-size: 20px; background: #222; position: relative; right: 14px !important; bottom: 11px !important; border-radius: 3px !important; } #topcontrol:after { /*top: -2px;*/ left: 8.5px; content: "\f106"; position: absolute; text-align: center; font-family: FontAwesome; } #topcontrol:hover { color: #fff; background: #18ba9b; -webkit-transition: all 0.3s ease-in-out; -moz-transition: all 0.3s ease-in-out; -o-transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out; } /* 側欄導航 */ .sideBox { padding: 10px; height: 220px; background: #fff; margin-bottom: 10px; overflow: hidden; } .sideBox .hd { height: 30px; line-height: 30px; background: #f60; padding: 0 10px; text-align: center; overflow: hidden; } .sideBox .hd .more { color: #fff; } .sideBox .hd h3 span { font-weight: bold; font-size: 14px; color: #fff; } .sideBox .bd { padding: 5px 0 0; } #sideMenu .bd li { margin-bottom: 2px; height: 30px; line-height: 30px; text-align: center; overflow: hidden; } #sideMenu .bd li a { display: block; background: #EAE6DD; } #sideMenu .bd li a:hover { background: #D5CFBF; } /* 列表頁 */ #mainBox { margin-bottom: 10px; padding: 10px; background: #fff; overflow: hidden; } #mainBox .mHd { border-bottom: 2px solid #09c; height: 30px; line-height: 30px; } #mainBox .mHd h3 { display: initial; *display: inline; zoom: 1; padding: 0 15px; background: #09c; color: #fff; } #mainBox .mHd h3 span { color: #fff; font-size: 14px; font-weight: bold; } #mainBox .path { float: right; } /* 位置導航 */ .path { height: 30px; line-height: 30px; padding-left: 10px; } .path a, .path span { margin: 0 5px; } /* 文章列表 */ .newsList { padding: 10px; text-align: left; } .newsList li { background: url("../images/share/point.png") no-repeat 2px 14px; padding-left: 10px; height: 30px; line-height: 30px; } .newsList li a { display: inline-block; *display: inline; zoom: 1; font-size: 14px; } .newsList li .date { float: right; color: #999; } .newsList li.split { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px dotted #ddd; height: 0px; line-height: 0px; overflow: hidden; } /* 通用帶圖片的資訊列表_普通式 */ .picList { padding: 10px; text-align: left; } .picList li { margin: 0 5px; height: 190px; } h3.break { font-size: 16px; display: block; white-space: nowrap; word-wrap: normal; overflow: hidden; text-overflow: ellipsis; } h3.break > a { text-decoration: none; } </style> </head> <body> <div class="navbar-wrapper"> <div class="container"> <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="index.html" style="font-size:32px;">尚籌網-創意產品眾籌平臺</a> </div> <div id="navbar" class="navbar-collapse collapse" style="float:right;"> <ul class="nav navbar-nav navbar-right"> <li><a href="login.html" th:href="@{/auth/member/to/login/page}">登入</a></li> <li><a href="reg.html" th:href="@{/auth/member/to/reg/page}">註冊</a></li> <li><a>|</a></li> <li><a href="admin-login.html">管理員入口</a></li> </ul> </div> </div> </nav> </div> </div> <!-- Carousel ================================================== --> <div id="myCarousel" class="carousel slide" data-ride="carousel"> <!-- Indicators --> <ol class="carousel-indicators"> <li data-target="#myCarousel" data-slide-to="0" class="active"></li> <li data-target="#myCarousel" data-slide-to="1"></li> <li data-target="#myCarousel" data-slide-to="2"></li> </ol> <div class="carousel-inner" role="listbox"> <div class="item active" onclick="window.location.href='project.html'" style="cursor:pointer;"> <img src="img/carousel-1.jpg" alt="First slide"> </div> <div class="item" onclick="window.location.href='project.html'" style="cursor:pointer;"> <img src="img/carousel-2.jpg" alt="Second slide"> </div> <div class="item" onclick="window.location.href='project.html'" style="cursor:pointer;"> <img src="img/carousel-3.jpg" alt="Third slide"> </div> </div> <a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev"> <span class="glyphicon glyphicon-chevron-left"></span> <span class="sr-only">Previous</span> </a> <a class="right carousel-control" href="#myCarousel" role="button" data-slide="next"> <span class="glyphicon glyphicon-chevron-right"></span> <span class="sr-only">Next</span> </a> </div><!-- /.carousel --> <!-- Marketing messaging and featurettes ================================================== --> <!-- Wrap the rest of the page in another container to center all the content. --> <div class="container marketing"> <!-- Three columns of text below the carousel --> <div class="row"> <div class="col-lg-4"> <img class="img-circle" src="img/p1.jpg" alt="Generic placeholder image" style="width: 140px; height: 140px;"> <h2>智慧高清監控機器人</h2> <p>可愛的造型,攝像安防遠端互聯的全能設計,讓你隨時隨地守護您的家人,陪伴你的生活。</p> <p><a class="btn btn-default" href="project.html" role="button">專案詳情 »</a></p> </div><!-- /.col-lg-4 --> <div class="col-lg-4"> <img class="img-circle" src="img/p2.jpg" alt="Generic placeholder image" style="width: 140px; height: 140px;"> <h2>NEOKA智慧手環</h2> <p>要運動更要安全,這款、名為“蝶舞”的NEOKA-V9100智慧運動手環為“安全運動而生”。</p> <p><a class="btn btn-default" href="project.html" role="button">專案詳情 »</a></p> </div><!-- /.col-lg-4 --> <div class="col-lg-4"> <img class="img-circle" src="img/p3.png" alt="Generic placeholder image" style="width: 140px; height: 140px;"> <h2>驅蚊扣</h2> <p>隨處使用的驅蚊鈕釦,<br>解決夏季蚊蟲問題。</p> <p><a class="btn btn-default" href="project.html" role="button">專案詳情 »</a></p> </div><!-- /.col-lg-4 --> </div><!-- /.row --> <div th:if="${#strings.isEmpty(portal_data)}">沒有載入到任何廢了資訊</div> <div th:if="${not #strings.isEmpty(portal_data)}"> <div th:each="type : ${portal_data}" class="container"> <div class="row clearfix"> <div class="col-md-12 column"> <div class="box ui-draggable" id="mainBox"> <div class="mHd" style=""> <div class="path"> <a href="projects.html">更多...</a> </div> <h3> <label th:text="${type.name}">科技</label> <small style="color:#FFF;"th:text="${type.remark}">開啟智慧未來</small> </h3> </div> <div class="mBd" style="padding-top:10px;"> <div class="row"> <div th:if="${#strings.isEmpty(type.portalProjectVOList)}">沒有任何專案資訊</div> <div th:if="${not #strings.isEmpty(type.portalProjectVOList)}"> <div th:each="project : ${type.portalProjectVOList}" class="col-md-3"> <div class="thumbnail"> <img alt="300x200" th:src="${project.headPicturePath}" src="img/product-1.jpg"/> <div class="caption"> <h3 class="break"> <a th:href="'http://localhost:80/project/get/project/detail/'+${project.projectId}" href="project.html" th:text="${project.projectName}">活性富氫淨水直飲機</a> </h3> <p> <div style="float:left;"><i class="glyphicon glyphicon-screenshot" title="目標金額"></i> $<span th:text="${project.money}">20,000</span> </div> <div style="float:right;"><i title="截至日期" class="glyphicon glyphicon-calendar"></i> <span th:text="${project.deployDate}">2017-20-20</span> </div> </p> <br> <div class="progress" style="margin-bottom: 4px;"> <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" th:aria-valuemin="${project.percentage}" aria-valuemin="0" aria-valuemax="100" th:style="'width: '+${project.percentage}+'%'" style="width: 40%"> <span th:text="${project.percentage}+'%'">40% </span> </div> </div> <div><span style="float:right;"><i class="glyphicon glyphicon-star-empty"></i></span> <span><i class="glyphicon glyphicon-user" title="支援人數"></i> <span th:text="${project.supporter}">12345</span></span> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- FOOTER --> <div class="container"> <div class="row clearfix"> <div class="col-md-12 column"> <div id="footer"> <div class="footerNav"> <a rel="nofollow" href="http://www.atguigu.com">關於我們</a> | <a rel="nofollow" href="http://www.atguigu.com">服務條款</a> | <a rel="nofollow" href="http://www.atguigu.com">免責宣告</a> | <a rel="nofollow" href="http://www.atguigu.com">網站地圖</a> | <a rel="nofollow" href="http://www.atguigu.com">聯絡我們</a> </div> <div class="copyRight"> Copyright ?2017-2017atguigu.com 版權所有 </div> </div> </div> </div> </div> </div><!-- /.container --> <script src="jquery/jquery-2.1.1.min.js"></script> <script src="bootstrap/js/bootstrap.min.js"></script> <script src="script/docs.min.js"></script> <script src="script/back-to-top.js"></script> <script> $(".thumbnail img").css("cursor", "pointer"); $(".thumbnail img").click(function () { window.location.href = "project.html"; }); </script> </body> </html>
閘道器工程
依賴
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies>
主啟動類
@EnableZuulProxy @SpringBootApplication public class CrowdApplication { public static void main(String[] args) { SpringApplication.run(CrowdApplication.class, args); } }
配置檔案
server:
port: 80
spring:
application:
name: adom-crowd-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:1000/eureka
zuul:
ignored-services: "*"
sensitive-headers: "*" #在Zuul向其他微服務重定向時保持原本頭資訊(請求頭、響應頭)
routes:
crowd-portal:
service-id: adom-crowd-auth
path: /** #這裡一定要使用兩個"*"號,不然"/"路徑後面的多層路徑將無法訪問
配置域名
訪問效果
在瀏覽器輸入域名