idea构建简单的springcloud gateway
springcloud gateway的工程需要单独,不要使用父类的依赖
很简单的结构,简单使用这些就够了
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.4.RELEASE</version> </parent> <groupId>com.gateway</groupId> <artifactId>gateway-service</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--GateWay ⽹关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--引⼊webflux--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> <dependencyManagement> <!--spring cloud依赖版本管理--> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <!--编译插件--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> <!--打包插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
下面是配置文件
#eureka server服务端口 server: port: 9000 spring: application: name: gateway-service # 应用名称,应用名称会在Eureka中作为服务名称 cloud: #getway配置 ##### 动态路由设置时,uri以 lb: //开头(lb代表从注册中⼼获取服务),后⾯是需要转发到的服务名称 gateway: routes: # 路由可以有多个 - id: service-router1 # 我们⾃定义的路由 ID,保持唯⼀ #uri: http://127.0.0.1:8082 # ⽬标服务地址 部署多实例) 动态路由:uri配置的应该是⼀个服务名称,⽽不应该是⼀个具体的服务实例的地址 uri: lb://login-service # ⽬标服务地址 部署多实例) 动态路由:uri配置的应该是⼀个服务名称,⽽不应该是⼀个具体的服务实例的地址 # gateway⽹关从服务注册中⼼获取实例信息然后负载后路由 predicates: #断⾔:路由条件,Predicate 接受⼀个输⼊参数,返回⼀个布尔值结果。该接⼝包含多种默 认⽅法来将 Predicate 组合成其他复杂的逻辑(⽐如:与,或,⾮)。 - Path=/**
如果想使用application.properties这种形式,参考下图
说明下- Path=/login/**,这样把路径可以配置的更加细化些
package com.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @Description * @Author qiuxie * @Date 2021/8/3 0:10 */ @SpringBootApplication @EnableDiscoveryClient public class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class,args); } }
使用springcloud需要一个eureka注册中心,一个服务提供者
下面依次给出注册中心的
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>homework-parent</artifactId> <groupId>com.parent</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.eureka</groupId> <artifactId>eureka-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> </project>
package com.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @Description * @Author qiuxie * @Date 2021/7/30 0:09 */ @SpringBootApplication @EnableEurekaServer public class EurekaOneApplication { public static void main(String[] args) { SpringApplication.run(EurekaOneApplication.class,args); } } server.port=8761 spring.application.name=eureka-service eureka.instance.hostname=localhost eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8762 eureka.client.register-with-eureka=false eureka.client.fetch-registry=false
接下来是服务提供者
package com.login.controller.front; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; /** * @Description * @Author qiuxie * @Date 2021/7/24 0:10 */ @Controller public class LoginController { @RequestMapping("/login") public String login(){ return "login/login"; } // 跳转注册页面 @RequestMapping("/toRe") public String toRe() { return "login/re"; } }
package com.login; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @Description * @Author qiuxie * @Date 2021/7/24 0:09 */ @SpringBootApplication @EnableDiscoveryClient public class LoginApplication { /** * 定义管理员名称 */ public static String userAdmin = ""; public static void main(String[] args) { SpringApplication.run(LoginApplication.class,args); } }
<!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, maximum-scale=1, user-scalable=no"> <title>[[#{text.suffix}]]</title> <meta http-equiv="Cache-Control" content="no-siteapp"/> <link rel="shortcut icon" th:href="@{/img/favicon.ico}"/> <script type="text/javascript" th:src="@{/js/jquery-3.2.1.min.js}" ></script> <link rel="stylesheet" th:href="@{/css/amazeui.min.css}"/> <link rel="stylesheet" th:href="@{/css/app.css}"/> <style type="text/css"> .status{ width: 200px; height: 20px; color: #FFFF00; font-size:15px; } #addressTitle{ font-size: 5px; } </style> </head> <body> <div class="log"> <div class="am-g"> <div class="am-u-lg-3 am-u-md-6 am-u-sm-8 am-u-sm-centered log-content"> <h1 class="log-title am-animation-slide-top"> 不忘初心 <p id="status" class="status"></p> </h1> <span id="time"></span> <br> <form class="am-form" id="loginForm"> <div class="am-input-group am-radius am-animation-slide-left"> <input type="text" id="user" class="am-radius" autocomplete="off" placeholder="请输入用户名"/> <span class="am-input-group-label log-icon am-radius"><i class="am-icon-user am-icon-sm am-icon-fw"></i></span> </div> <br> <div class="am-input-group am-animation-slide-left log-animation-delay"> <input class="am-form-field am-radius log-input" id="pwd" placeholder="请输入密码" type="password"/> <span class="am-input-group-label log-icon am-radius"><i class="am-icon-lock am-icon-sm am-icon-fw"></i></span> </div> <label><input id="remember" type="checkbox">记住密码</label><br> <button type="button" class="am-btn am-btn-primary am-btn-block am-btn-lg am-radius am-animation-slide-bottom log-animation-delay" onclick="checkForm()"> 登 录 </button> <a href="/toRe">注册</a> <!--<a href="/user/toResetPwd">忘记密码?</a>--> </form> </div> </div> <!--<footer class="log-footer"> © [[#{text.year}]] Yourheart <a href="https://beian.miit.gov.cn/" target="_blank"> 鄂ICP备19016375号-[[#{text.icp}]] </a> </footer>--> </div> <script type="text/javascript"> //获取打开登录页面操作者的ip $(document).ready(function(){ var oUser = document.getElementById('user'); var oPswd = document.getElementById('pwd'); var oRemember = document.getElementById('remember'); //页面初始化时,如果帐号密码cookie存在则填充 if(getCookie('user') && getCookie('pwd')) { oUser.value = getCookie('user'); oPswd.value = getCookie('pwd'); oRemember.checked = true; } //复选框勾选状态发生改变时,如果未勾选则清除cookie oRemember.onchange = function() { if(!this.checked) { delCookie('user'); delCookie('pwd'); } }; }); $("#pwd").keydown(function() { if (event.keyCode == "13") { //keyCode=13是回车键;数字不同代表监听的按键不同 checkForm(); } }); //设置cookie function setCookie(name, value, day) { var date = new Date(); date.setDate(date.getDate() + day); document.cookie = name + '=' + value + ';expires=' + date; }; //获取cookie function getCookie(name) { var reg = RegExp(name + '=([^;]+)'); var arr = document.cookie.match(reg); if(arr) { return arr[1]; } else { return ''; } }; //删除cookie function delCookie(name) { setCookie(name, null, -1); }; function queryIp() { var result=""; var url="https://api.ipify.org/?format=json"; $.ajax({ url:url , type: "get", dataType: "json", async: false, success: function(rs) { result=rs.ip; return rs.ip; } }); return result; } function checkForm() { var oUser = document.getElementById('user'); var oPswd = document.getElementById('pwd'); if(remember.checked) { setCookie('user', oUser.value, 90); //保存帐号到cookie,有效期7天 setCookie('pwd', oPswd.value, 90); //保存密码到cookie,有效期7天 } $.ajax({ url: "/loginauth/login", type: "post", dataType: "json", /*指定ajax和servlet之间数据交互的格式*/ data: { username: oUser.value, password: oPswd.value, ip:queryIp() }, async: true, success: function(result) { if (result.code==100|result.code==101) { window.location.href = '/'; } else if(result.code==104||result.code==108){ window.location.href = '/loginauth/Safetycertification'; }else { var status=result.status; console.log(status) document.getElementById("status").innerHTML=status } } }); //************************ } </script> </body> </html>
<!DOCTYPE html> <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="shortcut icon" th:href="@{/img/favicon.ico}"/> <title>注册-[[#{text.suffix}]]</title> <link rel="stylesheet" th:href="@{/css/bootstrap.css}" /> <script type="text/javascript" th:src="@{/js/jquery-3.2.1.min.js}" ></script> <style type="text/css"> body{ background: #CCCCCC; } #div01{ width: 450px; height: 400px; background: #ccc; border: 2px solid #ccc; border-radius: 5%; float: none; margin: 0 auto; align-items: center; } #statusaa{ font-size:15px; color:yellow; } </style> </head> <body> <div class="container"> <br /> <div class="page-header"> <h1>注册 <small id="statusaa"></small> </h1> </div> <div id="div01"> <table class="table"> <tr> <td>用户名</td> <td> <input type="text" class="form-control" id="UserName" placeholder="请输入用户名" autocomplete="off"> </td> </tr> <tr> <td>密码</td> <td> <input type="password" class="form-control" id="passwords" placeholder="请输入密码"> </td> </tr> <tr> <td>密码</td> <td> <input type="password" class="form-control" id="passwordsa" placeholder="请再次输入密码"> </td> </tr> <tr> <td>邮箱</td> <td> <input type="email" class="form-control" id="email" placeholder="请输入邮箱" autocomplete="off"> </td> </tr> <tr> <td>验证码</td> <td> <!--<div class="form-group">--> <input id="code" class="form-control" type="password" autocomplete="off" placeholder="请输入验证码"> <input id="getCode" class="btn btn-default" type="button" value="获取验证码" onclick="sendMessages()"></input> <!-- </div>--> </td> </tr> <tr> <td colspan="2" align="center"> <button type="button" class="btn btn-primary " onclick="addUser()">注册</button> <a class="btn btn-default" th:href="@{/login}" role="button">返回</a> </td> </tr> </table> </div> </div> <script type="text/javascript"> var urls="/user"; var urls="/loginauth"; var InterValObj; //timer变量,控制时间 var count = 60; //间隔函数,1秒执行 var curCount; //当前剩余秒数 var code = ""; //验证码 var codeLength = 6; //验证码长度 function queryIp() { var result=""; var url="https://api.ipify.org/?format=json"; $.ajax({ url:url , type: "get", dataType: "json", async: false, success: function(rs) { result=rs.ip; return rs.ip; } }); return result; } //验证码和手机号插入数据库 function sendMessages() { var email = $("#email").val(); curCount = count; if(email != "") { //设置button效果,开始计时 $("#getCode").attr("disabled", "true"); $("#getCode").val("请在" + curCount + "秒内输入"); InterValObj = window.setInterval(SetRemainTimes, 1000); //启动计时器,1秒执行一次 // var result=window.prompt("请输入秘钥:"); //向后台发送处理数据 $.ajax({ url: urls+"/byEmailgetCheckCode.shtml", type: "post", dataType: "json", /*指定ajax和servlet之间数据交互的格式*/ data: { email: email }, async: true, success: function(rs) { var code=rs.code; var message=rs.message; if(code>=1){ document.getElementById("status").innerHTML=message }else{ document.getElementById("status").innerHTML=message } } }); } else { alert("邮箱不能为空!!!!!!"); } } //timer处理函数 function SetRemainTimes() { if(curCount == 0) { window.clearInterval(InterValObj); //停止计时器 $("#getCode").removeAttr("disabled"); //启用按钮 $("#getCode").val("重新发送验证码"); code = ""; //清除验证码。如果不清除,过时间后,输入收到的验证码依然有效 } else { curCount--; $("#getCode").val("请在" + curCount + "秒内输入"); } } //开始按钮点击事件 $("#start").click(function() { window.location.href = "regafter.html?phone=" + $("#phone").val(); }) //用户注册开始 function addUser(){ var user=$("#UserName").val(); var pwd=$("#passwords").val(); var pwda=$("#passwordsa").val(); var email=$("#email").val(); if (pwd==pwda){ //****************** if(user.length!=0&&pwd.length!=0&&email.length!=0&&pwda.length!=0){ $.ajax({ url:urls+"/addUser.shtml", type:"post", dataType:"json",/*指定ajax和servlet之间数据交互的格式*/ data:{ user:user, pwd:pwd, email:email, ip:queryIp() }, async:true, success:function(rs){ if(rs.code==1){ window.location.href="/userLogin"; }else{ var status=rs.status; document.getElementById("statusaa").innerHTML=status } } }); }else{ alert("注册用户名或密码,邮箱不允许为空..") } //********************* }else{ alert("两次密码输入不一致!") } } </script> </body> </html>
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>homework-parent</artifactId> <groupId>com.parent</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.login</groupId> <artifactId>login-service</artifactId> <dependencies> <!--客户端--> <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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 热部署模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <!-- 这个需要为 true 热部署才有效 --> </dependency> </dependencies> </project>
浏览器输入http://127.0.0.1:9000/login
app.css
html { width:100%; height:100%; } .bg-grey { background-color: #f7f7f7 } body { width:100%; height:100%; } .log { width:100%; height:100%; background:url(/img/f10.jpg) #000 no-repeat; /* background:#D2B48C; */ background-size:100% 100%; color:#ffffff; } @media only screen and (max-width:640px) { .log { background-size:180% 100%; background-position:top right; } .log-title { display:none; } } .log-title { font-size:4rem; } .log-content { margin-top:15%; text-align:center; } .log-button { background-color:transparent; border-radius:8px; border:2px solid #ffffff; display:inline-block; cursor:pointer; color:#ffffff; text-decoration:none; text-shadow:0px 1px 0px #2f6627; } .log-button:hover { background-color:#0e90d2; border:2px solid #0e90d2; color:#ffffff; } .log-button:active { position:relative; top:1px; } .log-header,.log-re { background-color:transparent; position:absolute; top:0; color:#ffffff; } .log-header { display: block; height: 50px; width: 165px; margin-left:10%; text-indent: -9999px; background-size: 125px 24px; } .log-header:hover { height: 50px; width: 165px; margin-left:10%; text-indent: -9999px; background: url(http://s.amazeui.org/media/i/brand/amazeui-cw.png) left center no-repeat; background-size:125px 24px; } .log a { color:#fff; } .log-re { right:10%; top:1%; } .log-icon { background-color:transparent; color:#ffffff; } .log-animation-delay { -webkit-animation-delay: 200ms; animation-delay: 200ms; } .log-animation-delay-a { -webkit-animation-delay: 300ms; animation-delay: 300ms; } .log-animation-delay-b { -webkit-animation-delay: 500ms; animation-delay: 500ms; } .log-alert { clear:both; width:100%; height:28px; line-height:28px; padding-top:0; position:absolute; top:20px; left:0; display:block; } .log-footer { position:absolute; bottom:10px; width:100%; text-align:center; } /** * blog css * a:hover: #10D07A * 基本色:#333 * 或者 #3d3d3d * bgcolor:#10D07A , color:#fff * blog-color 单独的颜色突出 * .blog-bor border:1px solid #e5e5e5 * css复用 与 规范化 */ a:hover { color:#10D07A; } .blog-header { margin-top:3rem; } @media only screen and (max-width:640px) { .blog-header { margin-top:1rem; } .blog-nav li { text-align:center; } } #blog hr { margin:0.6rem 0; } .blog-nav { padding:0 1.3rem; } .blog-nav li a:hover{ background-color:#fff; color:#10D07A; } .blog-button { width:95%; height:100%; margin-left:1.5rem; background-color:#10D07A; } .am-dropdown-content li a{ background-color:transparent; } .am-dropdown-content li a:hover { background-color:#10D07A; } .blog-text-center { text-align:center; } .blog-bor { border:1px solid #e5e5e5; } .am-topbar-nav>li.am-active>a, .am-topbar-nav>li.am-active>a:focus, .am-topbar-nav>li.am-active>a:hover { border-radius: 0; color: #10D07A; background: 0 0; text-align:center; } .am-topbar-nav>li>a:hover:after { opacity: 0; } @media only screen and (min-width: 641px) { .am-topbar-nav>li.am-active>a:after { opacity: 0; } } @media only screen and (min-width: 1200px) { .blog-fixed { max-width: 1200px; } } .blog-entry-img { padding:0; max-width:100%; height:auto; } .blog-entry-article { margin:3rem 0; padding-bottom: 3rem; border-bottom: 1px solid #e5e5e5; } @media only screen and (max-width:640px) { .blog-entry-article { padding-bottom:1rem; text-align:center; } } .blog-entry-text { padding:0 1rem; } .blog-entry-text h1 { margin-top:0; color:#3d3d3d; } .blog-sidebar { margin-top:3rem; padding:0 1.5rem 0 3rem; } .blog-title { margin-top:-1.5rem; } .blog-title span{ background-color:#fff; padding:0 1.5rem; } .blog-sidebar-widget { padding:0 2rem; margin-bottom:4rem; text-align:center; } h1 span{ color:#333; } .blog-icon { width:3.4rem; border:1px solid #e5e5e5; padding:0.5rem; color:#3d3d3d; } .blog-icon:hover { color:#fff; background:#10D07A; border:1px solid #10D07A; } .blog-color { /**color:#10D07A;**/ } .blog-continue { color:#000; border:0.2rem solid gray; padding:0.5rem 1rem; font-weight:bold; display:none; } .blog-continue:hover { background-color:#10D07A; color:#fff; border:0.1rem #fff; } .blog-tag { background:#F3F3F3; margin:0.15rem 0.15rem; line-height:2.5rem; float:left; border: 1px solid #eee; padding:0.2rem 0.8rem 0.2rem 0.8rem; } .blog-tag:hover { background:#10D07A; color:#fff; } .blog-clear-margin { margin-left:0rem !important; margin-right:0rem !important; } .blog-clear-padding { padding:0 0 1.5rem 0 !important; } .blog-tag-left { text-align:left; } .blog-footer { padding:3rem 0 2rem 0; margin-top:5rem; background-color:#252525; color:#fff !important } .blog-footer-padding { padding:3rem 0; } .blog-footer a{ color:#fff; } .blog-footer span { color:#fff; } /** * blog-article-sidebar * */ .blog-article-p { margin:3rem 0; } .blog-author-img { width:8rem; height:8rem; } @media only screen and (max-width:641px) { .blog-author-img { width:6rem; height:6rem; } } .blog-article-margin { margin:3rem 0; } .blog-clear-left { padding-left: 0; } .blog-clear-right { padding-right:0; } .blog-slider-desc { width:50%; height:50%; overflow:hidden; border:0.3rem solid #fff; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); -webkit-transform:translate(-50%,-50%);; background-color:transparent; } .blog-slider-con { position:absolute; left:0.5%; top:1%; width:99%; height:98%; border:0.3rem solid #fff; padding:3rem 8rem; background-color:#fff; } /** * bug: * width:100%; height:100%; * margin: 1% 或者 1rem ; * 此处的定位出现问题。 */ .blog-h-margin { margin:0; } .am-slider-carousel li { margin-right: 25px; } .blog-comment { padding-left:0.625rem; } .img-layout { width:300px; height:200px; } #container { width: 100%; margin: auto; } #container div { -webkit-box-shadow: 0 4px 15px -5px #555; box-shadow: 0 4px 15px -5px #555; background-color: #fff; width:220px; padding:2px; margin:5px; } #container > div img { padding: 0px; display: block; width: 100%; } .time-year { margin-bottom:3rem; margin-top:3rem; } .timeline-year li { list-style: none; } .timeline-span { border-left:2px solid #10D07A; }
amazeui.min.css