title: 暑假最后几天!肝爆(手写)一个Spring之Day2
date: 2022-08-14 13:26:59
categories:
- 手写spring
Day02—Spring开撸前之环境准备
基础配置
-
一开始肯定多少是有点懵b的,但是咱冷静一下整理思路。。。
-
新建一个Maven web项目,不会看教程:http://t.csdn.cn/YugX1,后面怎么启动就是打war包在tomcat上运行
-
用application.properties代替application.xml(网上常见做法)
-
pom.xml配置
<?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> <groupId>com.czh</groupId> <artifactId>luelueking_Spring_Source</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <servlet.api.version>2.4</servlet.api.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet.api.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> </dependency> </dependencies> </project>
-
配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <display-name>luelueking Spring Application</display-name> <servlet> <servlet-name>mymvc</servlet-name> <servlet-class>com.czh.spring.framework.webmvc.servlet.MyDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mymvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
-
创建servlet作为MVC的入口
package com.czh.spring.framework.webmvc.servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class MyDispatcherServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } @Override public void init(ServletConfig config) throws ServletException { super.init(config); } }
-
在来点注解(注意Target作用域)
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAutowired { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyController { String value() default ""; } @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestMapping { String value() default ""; } @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestParam { String value() default ""; boolean required() default true; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyService { String value() default ""; }
业务代码
-
整个查询业务
package com.czh.spring.demo.service; /** * 查询业务 */ public interface QueryService { /** * 查询 */ public String query(String name); }
package com.czh.spring.demo.service.impl; import com.czh.spring.demo.service.QueryService; import com.czh.spring.framework.annotation.MyService; import lombok.extern.slf4j.Slf4j; import java.text.SimpleDateFormat; import java.util.Date; @Slf4j @MyService public class QueryServiceImpl implements QueryService { /** * 查询 */ @Override public String query(String name) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(new Date()); String json = "{name:\"" + name + "\",time:\"" + time + "\"}"; log.info("这是在业务方法中打印的:" + json); return json; } }
-
CURD都补上
package com.czh.spring.demo.service; public interface ModifyService { /** * 增加 */ public String add(String name, String addr) throws Exception; /** * 修改 */ public String edit(Integer id, String name); /** * 删除 */ public String remove(Integer id); }
package com.czh.spring.demo.service.impl; import com.czh.spring.demo.service.ModifyService; public class ModifyServiceImpl implements ModifyService { /** * 增加 */ @Override public String add(String name, String addr) throws Exception { return "modifyService add,name=" + name + ",addr=" + addr; } /** * 修改 */ @Override public String edit(Integer id, String name) { return "modifyService edit,id=" + id + ",name=" + name; } /** * 删除 */ @Override public String remove(Integer id) { return "modifyService id=" + id; } }
-
整个Controller整合CRUD
package com.czh.spring.demo.controller; import com.czh.spring.demo.service.ModifyService; import com.czh.spring.demo.service.QueryService; import com.czh.spring.framework.annotation.*; import com.czh.spring.framework.webmvc.MyModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * 公布接口url * */ @MyController @MyRequestMapping("/web") public class CRUDController { @MyAutowired QueryService queryService; @MyAutowired ModifyService modifyService; @MyRequestMapping("/query.json") public MyModelAndView query(HttpServletRequest request, HttpServletResponse response, @MyRequestParam("name") String name){ String result = queryService.query(name); return out(response,result); } @MyRequestMapping("/add.json") public MyModelAndView add(HttpServletRequest request,HttpServletResponse response, @MyRequestParam("name") String name,@MyRequestParam("address") String address){ String result = null; try { result = modifyService.add(name,address); return out(response,result); } catch (Exception e) { // e.printStackTrace(); Map<String,Object> model = new HashMap<String,Object>(); model.put("detail",e.getCause().getMessage()); // System.out.println(Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]","")); model.put("stackTrace", Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]","")); return new MyModelAndView("500",model); } } @MyRequestMapping("/remove.json") public MyModelAndView remove(HttpServletRequest request,HttpServletResponse response, @MyRequestParam("id") Integer id){ String result = modifyService.remove(id); return out(response,result); } @MyRequestMapping("/edit.json") public MyModelAndView edit(HttpServletRequest request,HttpServletResponse response, @MyRequestParam("id") Integer id, @MyRequestParam("name") String name){ String result = modifyService.edit(id,name); return out(response,result); } private MyModelAndView out(HttpServletResponse resp,String str){ try { resp.getWriter().write(str); } catch (IOException e) { e.printStackTrace(); } return null; } }
-
整个pageController用来测试模版渲染
package com.czh.spring.demo.controller; import com.czh.spring.demo.service.QueryService; import com.czh.spring.framework.annotation.MyAutowired; import com.czh.spring.framework.annotation.MyController; import com.czh.spring.framework.annotation.MyRequestMapping; import com.czh.spring.framework.annotation.MyRequestParam; import com.czh.spring.framework.webmvc.MyModelAndView; import java.util.HashMap; import java.util.Map; @MyController @MyRequestMapping("/") public class PageController { @MyAutowired QueryService queryService; @MyRequestMapping("/first.html") public MyModelAndView query(@MyRequestParam("name") String name) { String result = queryService.query(name); Map<String, Object> model = new HashMap<>(); model.put("name", name); model.put("hobby","吃屎"); return new MyModelAndView("first.html", model); } }
-
概览
layouts整合前端资源测试
-
我用的比较骚的404.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>404</title> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="Access-Control-Allow-Origin" content="*"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <link rel="stylesheet" href="/lib/layui/css/layui.css" media="all"> <style> html{background: #fff;} .error .clip .shadow {height:180px;} .error .clip:nth-of-type(2) .shadow {width:130px;} .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:250px;} .error .digit {width:150px;height:150px;line-height:150px;font-size:120px;font-weight:bold;} .error h2 {font-size:32px;} .error .msg {top:-190px;left:30%;width:80px;height:80px;line-height:80px;font-size:32px;} .error span.triangle {top:70%;right:0%;border-left:20px solid #535353;border-top:15px solid transparent;border-bottom:15px solid transparent;} .error .container-error-404 {top: 50%;margin-top: 250px;position:relative;height:250px;padding-top:40px;} .error .container-error-404 .clip {display:inline-block;transform:skew(-45deg);} .error .clip .shadow {overflow:hidden;} .error .clip:nth-of-type(2) .shadow {overflow:hidden;position:relative;box-shadow:inset 20px 0px 20px -15px rgba(150,150,150,0.8),20px 0px 20px -15px rgba(150,150,150,0.8);} .error .clip:nth-of-type(3) .shadow:after,.error .clip:nth-of-type(1) .shadow:after {content:"";position:absolute;right:-8px;bottom:0px;z-index:9999;height:100%;width:10px;background:linear-gradient(90deg,transparent,rgba(173,173,173,0.8),transparent);border-radius:50%;} .error .clip:nth-of-type(3) .shadow:after {left:-8px;} .error .digit {position:relative;top:8%;color:white;background:#1aa094;border-radius:50%;display:inline-block;transform:skew(45deg);} .error .clip:nth-of-type(2) .digit {left:-10%;} .error .clip:nth-of-type(1) .digit {right:-20%;} .error .clip:nth-of-type(3) .digit {left:-20%;} .error h2 {font-size:24px;color:#A2A2A2;font-weight:bold;padding-bottom:20px;} .error .tohome {font-size:16px;color:#07B3F9;} .error .msg {position:relative;z-index:9999;display:block;background:#535353;color:#A2A2A2;border-radius:50%;font-style:italic;} .error .triangle {position:absolute;z-index:999;transform:rotate(45deg);content:"";width:0;height:0;} @media(max-width:767px) {.error .clip .shadow {height:100px;} .error .clip:nth-of-type(2) .shadow {width:80px;} .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:100px;} .error .digit {width:80px;height:80px;line-height:80px;font-size:52px;} .error h2 {font-size:18px;} .error .msg {top:-110px;left:15%;width:40px;height:40px;line-height:40px;font-size:18px;} .error span.triangle {top:70%;right:-3%;border-left:10px solid #535353;border-top:8px solid transparent;border-bottom:8px solid transparent;} .error .container-error-404 {height:150px;} } </style> </head> <body> <div class="error"> <div class="container-floud"> <div style="text-align: center"> <div class="container-error-404"> <div class="clip"> <div class="shadow"> <span class="digit thirdDigit"></span> </div> </div> <div class="clip"> <div class="shadow"> <span class="digit secondDigit"></span> </div> </div> <div class="clip"> <div class="shadow"> <span class="digit firstDigit"></span> </div> </div> <div class="msg">OH! <span class="triangle"></span> </div> </div> <h2 class="h1">很抱歉,你访问的页面找不到了</h2> </div> </div> </div> <script src="/lib/layui/layui.js" charset="utf-8"></script> <script> function randomNum() { return Math.floor(Math.random() * 9) + 1; } var loop1, loop2, loop3, time = 30, i = 0, number; loop3 = setInterval(function () { if (i > 40) { clearInterval(loop3); document.querySelector('.thirdDigit').textContent = 4; } else { document.querySelector('.thirdDigit').textContent = randomNum(); i++; } }, time); loop2 = setInterval(function () { if (i > 80) { clearInterval(loop2); document.querySelector('.secondDigit').textContent = 0; } else { document.querySelector('.secondDigit').textContent = randomNum(); i++; } }, time); loop1 = setInterval(function () { if (i > 100) { clearInterval(loop1); document.querySelector('.firstDigit').textContent = 4; } else { document.querySelector('.firstDigit').textContent = randomNum(); i++; } }, time); </script> </body> </html>
-
我用的比较骚的500.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>404</title> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="Access-Control-Allow-Origin" content="*"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <link rel="stylesheet" href="/lib/layui/css/layui.css" media="all"> <style> html{background: #fff;} .error .clip .shadow {height:180px;} .error .clip:nth-of-type(2) .shadow {width:130px;} .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:250px;} .error .digit {width:150px;height:150px;line-height:150px;font-size:120px;font-weight:bold;} .error h2 {font-size:32px;} .error .msg {top:-190px;left:30%;width:80px;height:80px;line-height:80px;font-size:32px;} .error span.triangle {top:70%;right:0%;border-left:20px solid #535353;border-top:15px solid transparent;border-bottom:15px solid transparent;} .error .container-error-404 {top: 50%;margin-top: 250px;position:relative;height:250px;padding-top:40px;} .error .container-error-404 .clip {display:inline-block;transform:skew(-45deg);} .error .clip .shadow {overflow:hidden;} .error .clip:nth-of-type(2) .shadow {overflow:hidden;position:relative;box-shadow:inset 20px 0px 20px -15px rgba(150,150,150,0.8),20px 0px 20px -15px rgba(150,150,150,0.8);} .error .clip:nth-of-type(3) .shadow:after,.error .clip:nth-of-type(1) .shadow:after {content:"";position:absolute;right:-8px;bottom:0px;z-index:9999;height:100%;width:10px;background:linear-gradient(90deg,transparent,rgba(173,173,173,0.8),transparent);border-radius:50%;} .error .clip:nth-of-type(3) .shadow:after {left:-8px;} .error .digit {position:relative;top:8%;color:white;background:#1aa094;border-radius:50%;display:inline-block;transform:skew(45deg);} .error .clip:nth-of-type(2) .digit {left:-10%;} .error .clip:nth-of-type(1) .digit {right:-20%;} .error .clip:nth-of-type(3) .digit {left:-20%;} .error h2 {font-size:24px;color:#A2A2A2;font-weight:bold;padding-bottom:20px;} .error .tohome {font-size:16px;color:#07B3F9;} .error .msg {position:relative;z-index:9999;display:block;background:#535353;color:#A2A2A2;border-radius:50%;font-style:italic;} .error .triangle {position:absolute;z-index:999;transform:rotate(45deg);content:"";width:0;height:0;} @media(max-width:767px) {.error .clip .shadow {height:100px;} .error .clip:nth-of-type(2) .shadow {width:80px;} .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:100px;} .error .digit {width:80px;height:80px;line-height:80px;font-size:52px;} .error h2 {font-size:18px;} .error .msg {top:-110px;left:15%;width:40px;height:40px;line-height:40px;font-size:18px;} .error span.triangle {top:70%;right:-3%;border-left:10px solid #535353;border-top:8px solid transparent;border-bottom:8px solid transparent;} .error .container-error-404 {height:150px;} } </style> </head> <body> <div class="error"> <div class="container-floud"> <div style="text-align: center"> <div class="container-error-404"> <div class="clip"> <div class="shadow"> <span class="digit thirdDigit"></span> </div> </div> <div class="clip"> <div class="shadow"> <span class="digit secondDigit"></span> </div> </div> <div class="clip"> <div class="shadow"> <span class="digit firstDigit"></span> </div> </div> <div class="msg">OH! <span class="triangle"></span> </div> </div> <h2 class="h1">o(╥﹏╥)o很抱歉,系统错误咯~~ 赶紧联系管理员吧</h2> <h2 class="h1">Message:¥{detail}</h2> <h2 class="h1">StackTrace:¥{stackTrace}</h2> <h2 class="h1">Copyright@luelueking</h2> </div> </div> </div> <script src="/lib/layui/layui.js" charset="utf-8"></script> <script> function randomNum() { return Math.floor(Math.random() * 9) + 1; } var loop1, loop2, loop3, time = 30, i = 0, number; loop3 = setInterval(function () { if (i > 40) { clearInterval(loop3); document.querySelector('.thirdDigit').textContent = 5; } else { document.querySelector('.thirdDigit').textContent = randomNum(); i++; } }, time); loop2 = setInterval(function () { if (i > 80) { clearInterval(loop2); document.querySelector('.secondDigit').textContent = 0; } else { document.querySelector('.secondDigit').textContent = randomNum(); i++; } }, time); loop1 = setInterval(function () { if (i > 100) { clearInterval(loop1); document.querySelector('.firstDigit').textContent = 0; } else { document.querySelector('.firstDigit').textContent = randomNum(); i++; } }, time); </script> </body> </html>
-
我用的比较骚的用来测试模版渲染的first.html
注意模版为¥{}的类型
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>springMVC模版渲染测试用例</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <div> <!-- 注意这里的¥{}--> <h1>I'm ¥{name},I like ¥{hobby}</h1> </div> <div class="loader"> <div class="track"> <div class="mouse"></div> </div> <div class="face"> <div class="ears-container"></div> <div class="eyes-container"> <div class="eye"></div> <div class="eye"></div> </div> <div class="phiz"> <div class="nose"></div> <div class="lip"></div> <div class="mouth"></div> </div> </div> </div> <style> @import url("https://fonts.googleapis.com/css?family=Cabin+Sketch:400,700"); @import url("https://fonts.googleapis.com/css?family=Cabin+Sketch:400,700|Open+Sans|Oswald"); .title-box { position: relative; margin: auto; display: block; width: 400px; margin-top: 10%; background: none; z-index:999; border-bottom-color: transparent; } .btn-bubble { color: white; background-color: #6da0e0; background-repeat: no-repeat; } .btn-bubble:hover, .btn-bubble:focus { -webkit-animation: bubbles 1s forwards ease-out; animation: bubbles 1s forwards ease-out; background: radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 52% 125% / 1.2em 1.2em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 67% 133% / 0.66em 0.66em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 64% 93% / 1.17em 1.17em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 22% 88% / 1.04em 1.04em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 43% 95% / 0.87em 0.87em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 97% 116% / 0.62em 0.62em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 62% 97% / 0.64em 0.64em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 87% 135% / 0.68em 0.68em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) -4% 89% / 0.57em 0.57em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 89% 88% / 0.65em 0.65em, radial-gradient(circle at center, rgba(0, 0, 0, 0) 30%, #eeeeff 60%, #eeeeff 65%, rgba(0, 0, 0, 0) 70%) 6% 144% / 0.77em 0.77em; background-color: #6da0e0; background-repeat: no-repeat; } @-webkit-keyframes bubbles { 100% { background-position: 45% -182%, 61% -215%, 62% -196%, 18% -318%, 51% -86%, 88% -292%, 66% -244%, 89% -313%, -9% 9%, 99% -107%, 16% -282%; box-shadow: inset 0 -6.5em 0 #0072c4; } } @keyframes bubbles { 100% { background-position: 45% -182%, 61% -215%, 62% -196%, 18% -318%, 51% -86%, 88% -292%, 66% -244%, 89% -313%, -9% 9%, 99% -107%, 16% -282%; box-shadow: inset 0 -6.5em 0 #0072c4; } } body { background: #10192d; display: flex; min-height: 100vh; justify-content: center; align-content: center; align-items: center; } .btn { text-decoration: none; padding: 1em 2em; display: block; text-decoration: none; padding: 1em 2em; margin: 0 auto; text-align: center; } h1 { text-align: center; font-family: 'Cabin Sketch', cursive; font-size: 90px; margin-top: 0px; color: #333; margin-bottom: 20px; } @-webkit-keyframes rotate { 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @-moz-keyframes rotate { 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @-o-keyframes rotate { 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @keyframes rotate { 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @-webkit-keyframes hideEye { 0%, 10%, 85% { margin-top: 0; height: 50px; } 30%, 65% { margin-top: 20px; height: 30px; } } @-moz-keyframes hideEye { 0%, 10%, 85% { margin-top: 0; height: 50px; } 30%, 65% { margin-top: 20px; height: 30px; } } @-o-keyframes hideEye { 0%, 10%, 85% { margin-top: 0; height: 50px; } 30%, 65% { margin-top: 20px; height: 30px; } } @keyframes hideEye { 0%, 10%, 85% { margin-top: 0; height: 50px; } 30%, 65% { margin-top: 20px; height: 30px; } } @-webkit-keyframes blink { 0%, 10%, 85% { bottom: 0; } 30%, 65% { bottom: 20px; } 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @-moz-keyframes blink { 0%, 10%, 85% { bottom: 0; } 30%, 65% { bottom: 20px; } 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @-o-keyframes blink { 0%, 10%, 85% { bottom: 0; } 30%, 65% { bottom: 20px; } 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } @keyframes blink { 0%, 10%, 85% { bottom: 0; } 30%, 65% { bottom: 20px; } 0% { transform: rotate(-0.08turn); } 100% { transform: rotate(-1.08turn); } } body { margin: 0; background: #5e4674; overflow: hidden; } body .loader { position: absolute; left: 50%; bottom: 8%; width: 260px; height: 260px; margin-left: -130px; margin-top: -130px; } body .loader .track { width: 100%; height: 100%; border: solid #251c1c; border-width: 5px 5px 3px 0; border-top-color: transparent; border-radius: 50%; margin-left: -3px; margin-top: -3px; -webkit-animation: rotate 3s infinite linear; -moz-animation: rotate 3s infinite linear; -o-animation: rotate 3s infinite linear; animation: rotate 3s infinite linear; } body .loader .track .mouse { position: absolute; right: 31px; top: 18px; width: 25px; height: 25px; background: #251c1c; border-radius: 80% 0 55% 50% / 55% 0 80% 50%; transform: rotate(-95deg); } body .loader .track .mouse:before, body .loader .track .mouse:after { position: absolute; content: ''; width: 9px; height: 9px; border-radius: 50%; background: inherit; } body .loader .track .mouse:before { left: 5px; top: -4px; } body .loader .track .mouse:after { left: 20px; top: 11px; } body .loader .face { position: absolute; left: 50%; top: 50%; width: 130px; height: 130px; margin-left: -65px; margin-top: -65px; } body .loader .face:before, body .loader .face:after { position: absolute; content: ''; width: 50%; height: 100%; } body .loader .face:before { background: #c8c6c9; border-top-left-radius: 65px; border-bottom-left-radius: 55px; } body .loader .face:after { left: 50%; background: #d0ced1; border-top-right-radius: 65px; border-bottom-right-radius: 55px; } body .loader .face .ears-container { position: absolute; top: -8px; width: 130px; height: 50px; } body .loader .face .ears-container:before, body .loader .face .ears-container:after { position: absolute; content: ''; width: 0; height: 0; border-top: 35px solid transparent; border-bottom: 35px solid transparent; } body .loader .face .ears-container:before { border-left: 35px solid #c8c6c9; } body .loader .face .ears-container:after { right: 0; border-right: 35px solid #c8c6c9; } body .loader .face .eyes-container { position: absolute; overflow: hidden; left: 50%; top: 30px; width: 106px; height: 50px; margin-left: -53px; z-index: 1; -webkit-animation: hideEye 3s infinite linear; -moz-animation: hideEye 3s infinite linear; -o-animation: hideEye 3s infinite linear; animation: hideEye 3s infinite linear; } body .loader .face .eyes-container .eye { position: relative; bottom: 0; float: left; width: 50px; height: 50px; border-radius: 50%; color: #c8c6c9; background: white; -webkit-animation: blink 3s infinite linear; -moz-animation: blink 3s infinite linear; -o-animation: blink 3s infinite linear; animation: blink 3s infinite linear; } body .loader .face .eyes-container .eye:after { position: absolute; content: ''; top: 4px; right: 14px; width: 12px; height: 12px; border-radius: inherit; background: #838091; } body .loader .face .eyes-container .eye:last-child { float: right; color: #d0ced1; } body .loader .face .phiz { position: absolute; left: 50%; top: 66px; width: 32px; height: 48px; margin-left: -16px; z-index: 1; } body .loader .face .phiz .nose { width: 100%; height: 15px; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-left-radius: 25px; border-bottom-right-radius: 25px; background: #838091; } body .loader .face .phiz .lip { position: relative; left: 50%; width: 4px; height: 12px; margin-left: -2px; background: #838091; } body .loader .face .phiz .lip:before { position: absolute; content: ''; width: 100%; height: 5px; background: #767385; } body .loader .face .phiz .mouth { position: relative; left: 50%; width: 20px; height: 6px; margin-left: -13px; background: white; border: 3px solid #838091; border-bottom-right-radius: 12px; border-bottom-left-radius: 12px; } @media screen and (max-width: 900px){ h1 {font-size: 100px;} .btn {width: 50%;} } </style> </body> </html>
-
概览