-
登录注册
经过这段时间的努力,我们对Spring框架已经有了基本认识。是时候按下暂停键,学以致用,写个简单的小项目巩固一下我们至今所学的知识了。
这个小项目名为come-in,是个Web应用程序,实现了登录注册的功能。因此,整个网站总共包含三个页面:一个登录页面;一个注册页面;一个欢迎页面。如下:
登录页面:
注册页面:
欢迎页面:
实现这个网站用到的知识都是前文介绍过的。我们不会在这里讨论实现这个小项目所用的知识,而是把重心放在项目的实现上。为此,请打开IntelliJ IDEA,新建项目come-in,开始我们的网站实现之旅。
01.编写SQL脚本,运行SQL脚本,创建数据库。
1 CREATE DATABASE come_in DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; 2 3 USE come_in; 4 5 CREATE TABLE person ( 6 person_id INT NOT NULL AUTO_INCREMENT, # 数据库表ID 7 person_phone CHAR(11) NOT NULL, # 手机号码 8 person_password CHAR(68) NOT NULL, # 密码 9 person_name VARCHAR(12) NOT NULL, # 名字 10 person_time TIMESTAMP NOT NULL, # 注册时间 11 PRIMARY KEY (person_id) # 添加主键 12 ) ENGINE = INNODB;
02.在com.dream包下定义ErrorCode枚举。
1 package com.dream; 2 3 public enum ErrorCode { 4 SUCCESS(0), 5 ERROR_FATAL(1), 6 ERROR_DUPLICATE(2), 7 ERROR_CREDENTIAL(3); 8 9 private final int value; 10 11 ErrorCode(int value) { 12 this.value = value; 13 } 14 15 public int value() { 16 return value; 17 } 18 }
03.在com.dream包下定义Converter类。
1 package com.dream; 2 3 import java.util.*; 4 import java.text.*; 5 6 public final class Converter { 7 private Converter() {} 8 9 public static Integer toInteger(String value) { 10 try { 11 return value != null && value.length() > 0 ? Integer.parseInt(value) : null; 12 } catch (NumberFormatException e) { 13 return null; 14 } 15 } 16 17 public static Date toDate(String value) { 18 try { 19 return value != null ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value) : null; 20 } catch (ParseException e) { 21 return null; 22 } 23 } 24 }
04.在com.dream包下定义Validator类。
1 package com.dream; 2 3 import java.util.regex.*; 4 5 public final class Validator { 6 private static final String PATTERN_PHONE = "^1[0-9]{10}$"; 7 8 private Validator() {} 9 10 public static boolean validatePersonName(String value) { 11 if (value == null) { 12 return false; 13 } 14 if (value.length() > 12) { 15 return false; 16 } 17 return true; 18 } 19 20 public static boolean validatePersonPhone(String value) { 21 if (value == null) { 22 return false; 23 } 24 if (!Pattern.compile(PATTERN_PHONE).matcher(value).matches()) { 25 return false; 26 } 27 return true; 28 } 29 30 public static boolean validatePersonPassword(String value) { 31 if (value == null) { 32 return false; 33 } 34 if (value.length() < 6) { 35 return false; 36 } 37 if (value.length() > 48) { 38 return false; 39 } 40 return true; 41 } 42 }
05.在com.dream.repository包下定义AddPerson接口。
1 package com.dream.repository; 2 3 public interface AddPerson { 4 void access(String name, String phone, String password); 5 }
06.在com.dream.repository包下定义实现了AddPerson接口的AddPersonImpl类。
1 package com.dream.repository; 2 3 import javax.sql.*; 4 import org.springframework.jdbc.core.*; 5 import org.springframework.stereotype.*; 6 import org.springframework.beans.factory.annotation.*; 7 8 @Repository 9 public class AddPersonImpl implements AddPerson { 10 private static final String STATEMENT; 11 private JdbcTemplate jdbcTemplate = null; 12 13 @Autowired 14 public void setJdbcTemplate(DataSource dataSource) { 15 this.jdbcTemplate = new JdbcTemplate(dataSource); 16 } 17 18 @Override 19 public void access(String name, String phone, String password) { 20 this.jdbcTemplate.update(STATEMENT, preparedStatement -> { 21 preparedStatement.setString(1, phone); 22 preparedStatement.setString(2, password); 23 preparedStatement.setString(3, name); 24 }); 25 } 26 27 static { 28 STATEMENT = "" 29 + " INSERT INTO person" 30 + " (person_phone, person_password, person_name, person_time)" 31 + " VALUES" 32 + " (?, ?, ?, NOW())"; 33 } 34 }
07.在com.dream.repository包下定义CountPersonByPhone接口。
1 package com.dream.repository; 2 3 public interface CountPersonByPhone { 4 int access(String phone); 5 }
08.在com.dream.repository包下定义实现了CountPersonByPhone接口的CountPersonByPhoneImpl类。
1 package com.dream.repository; 2 3 import javax.sql.DataSource; 4 import org.springframework.jdbc.core.*; 5 import org.springframework.stereotype.*; 6 import org.springframework.beans.factory.annotation.*; 7 8 @Repository 9 public class CountPersonByPhoneImpl implements CountPersonByPhone { 10 private static final String STATEMENT; 11 private JdbcTemplate jdbcTemplate = null; 12 13 @Autowired 14 public void setJdbcTemplate(DataSource dataSource) { 15 this.jdbcTemplate = new JdbcTemplate(dataSource); 16 } 17 18 @Override 19 public int access(String phone) { 20 return this.jdbcTemplate.query(STATEMENT, preparedStatement -> { 21 preparedStatement.setString(1, phone); 22 }, resultSet -> resultSet.next() ? resultSet.getInt(1) : 0); 23 } 24 25 static { 26 STATEMENT = "SELECT COUNT(*) FROM person WHERE person_phone=?"; 27 } 28 }
09.在com.dream.repository包下定义QueryPersonByIdOut数据模型。
1 package com.dream.repository; 2 3 import java.util.*; 4 5 public class QueryPersonByIdOut { 6 private int personId = 0; 7 private String personName = null; 8 private Date personTime = null; 9 10 public int getPersonId() { 11 return this.personId; 12 } 13 14 public void setPersonId(int personId) { 15 this.personId = personId; 16 } 17 18 public String getPersonName() { 19 return this.personName; 20 } 21 22 public void setPersonName(String personName) { 23 this.personName = personName; 24 } 25 26 public Date getPersonTime() { 27 return this.personTime; 28 } 29 30 public void setPersonTime(Date personTime) { 31 this.personTime = personTime; 32 } 33 }
10.在com.dream.repository包下定义QueryPersonById接口。
1 package com.dream.repository; 2 3 public interface QueryPersonById { 4 QueryPersonByIdOut access(int id); 5 }
11.在com.dream.repository包下定义实现了QueryPersonById接口的QueryPersonByIdImpl类。
1 package com.dream.repository; 2 3 import javax.sql.*; 4 import org.springframework.jdbc.core.*; 5 import org.springframework.stereotype.*; 6 import org.springframework.beans.factory.annotation.*; 7 import com.dream.*; 8 9 @Repository 10 public class QueryPersonByIdImpl implements QueryPersonById { 11 private static final String STATEMENT; 12 private JdbcTemplate jdbcTemplate = null; 13 14 @Autowired 15 public void setJdbcTemplate(DataSource dataSource) { 16 this.jdbcTemplate = new JdbcTemplate(dataSource); 17 } 18 19 @Override 20 public QueryPersonByIdOut access(int id) { 21 return this.jdbcTemplate.query(STATEMENT, preparedStatement -> { 22 preparedStatement.setInt(1, id); 23 }, resultSet -> { 24 if (resultSet.next()) { 25 var out = new QueryPersonByIdOut(); 26 out.setPersonId(resultSet.getInt(1)); 27 out.setPersonName(resultSet.getString(2)); 28 out.setPersonTime(Converter.toDate(resultSet.getString(3))); 29 return out; 30 } else { 31 return null; 32 } 33 }); 34 } 35 36 static { 37 STATEMENT = "" 38 + " SELECT" 39 + " person_id, person_name, person_time" 40 + " FROM" 41 + " person" 42 + " WHERE" 43 + " person_id=?"; 44 } 45 }
12.在com.dream.repository包下定义QueryPersonIdByCredential接口。
1 package com.dream.repository; 2 3 public interface QueryPersonIdByCredential { 4 int access(String phone, String password); 5 }
13.在com.dream.repository包下定义实现了QueryPersonIdByCredential接口的QueryPersonIdByCredentialImpl类。
1 package com.dream.repository; 2 3 import javax.sql.*; 4 import org.springframework.jdbc.core.*; 5 import org.springframework.stereotype.*; 6 import org.springframework.beans.factory.annotation.*; 7 8 @Repository 9 public class QueryPersonIdByCredentialImpl implements QueryPersonIdByCredential { 10 private static final String STATEMENT; 11 private JdbcTemplate jdbcTemplate = null; 12 13 @Autowired 14 public void setJdbcTemplate(DataSource dataSource) { 15 this.jdbcTemplate = new JdbcTemplate(dataSource); 16 } 17 18 @Override 19 public int access(String phone, String password) { 20 return this.jdbcTemplate.query(STATEMENT, preparedStatement -> { 21 preparedStatement.setString(1, phone); 22 preparedStatement.setString(2, password); 23 }, resultSet -> resultSet.next() ? resultSet.getInt(1) : 0); 24 } 25 26 static { 27 STATEMENT = "" 28 + " SELECT" 29 + " person_id" 30 + " FROM" 31 + " person" 32 + " WHERE" 33 + " person_phone=? AND person_password=?"; 34 } 35 }
14.在com.dream.service包下定义BaseResult数据模型父类。
1 package com.dream.service; 2 3 import com.dream.*; 4 5 public class BaseResult { 6 private ErrorCode errorCode = ErrorCode.SUCCESS; 7 8 public ErrorCode getErrorCode() { 9 return this.errorCode; 10 } 11 12 public BaseResult(ErrorCode errorCode) { 13 this.errorCode = errorCode; 14 } 15 }
15.在com.dream.service包下定义ServiceLogonResult数据模型。
1 package com.dream.service; 2 3 import com.dream.*; 4 5 public class ServiceLogonResult extends BaseResult { 6 private int personId = 0; 7 8 public int getPersonId() { 9 return this.personId; 10 } 11 12 public void setPersonId(int personId) { 13 this.personId = personId; 14 } 15 16 public ServiceLogonResult(ErrorCode errorCode) { 17 super(errorCode); 18 } 19 }
16.在com.dream.service包下定义ServiceLogon接口。
1 package com.dream.service; 2 3 public interface ServiceLogon { 4 ServiceLogonResult process(String phone, String password); 5 }
17.在com.dream.service包下定义实现了ServiceLogon接口的ServiceLogonImpl类。
1 package com.dream.service; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.stereotype.*; 5 import com.dream.repository.*; 6 import com.dream.*; 7 8 @Service 9 public class ServiceLogonImpl implements ServiceLogon { 10 private QueryPersonIdByCredential queryPersonIdByCredential = null; 11 12 @Autowired 13 public void setQueryPersonIdByCredential(QueryPersonIdByCredential queryPersonIdByCredential) { 14 this.queryPersonIdByCredential = queryPersonIdByCredential; 15 } 16 17 @Override 18 public ServiceLogonResult process(String phone, String password) { 19 if (!Validator.validatePersonPhone(phone)) { 20 return new ServiceLogonResult(ErrorCode.ERROR_FATAL); 21 } 22 if (!Validator.validatePersonPassword(password)) { 23 return new ServiceLogonResult(ErrorCode.ERROR_FATAL); 24 } 25 26 var personId = queryPersonIdByCredential.access(phone, password); 27 if (personId <= 0) { 28 return new ServiceLogonResult(ErrorCode.ERROR_CREDENTIAL); 29 } 30 31 var serviceResult = new ServiceLogonResult(ErrorCode.SUCCESS); 32 serviceResult.setPersonId(personId); 33 return serviceResult; 34 } 35 }
18.在com.dream.service包下定义ServiceRegistry接口。
1 package com.dream.service; 2 3 public interface ServiceRegistry { 4 BaseResult process(String name, String phone, String password, String confirm); 5 }
19.在com.dream.service包下定义实现了ServiceRegistry接口的ServiceRegistryImpl类。
1 package com.dream.service; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.stereotype.*; 5 import com.dream.repository.*; 6 import com.dream.*; 7 8 @Service 9 public class ServiceRegistryImpl implements ServiceRegistry { 10 private CountPersonByPhone countPersonByPhone = null; 11 private AddPerson addPerson = null; 12 13 @Autowired 14 public void setCountPersonByPhone(CountPersonByPhone countPersonByPhone) { 15 this.countPersonByPhone = countPersonByPhone; 16 } 17 18 @Autowired 19 public void setAddPerson(AddPerson addPerson) { 20 this.addPerson = addPerson; 21 } 22 23 @Override 24 public BaseResult process(String name, String phone, String password, String confirm) { 25 if(!Validator.validatePersonName(name)) { 26 return new BaseResult(ErrorCode.ERROR_FATAL); 27 } 28 if(!Validator.validatePersonPhone(phone)) { 29 return new BaseResult(ErrorCode.ERROR_FATAL); 30 } 31 if(!Validator.validatePersonPassword(password)) { 32 return new BaseResult(ErrorCode.ERROR_FATAL); 33 } 34 if(!password.equals(confirm)) { 35 return new BaseResult(ErrorCode.ERROR_FATAL); 36 } 37 if(this.countPersonByPhone.access(phone) > 0) { 38 return new BaseResult(ErrorCode.ERROR_DUPLICATE); 39 } 40 41 this.addPerson.access(name, phone, password); 42 return new BaseResult(ErrorCode.SUCCESS); 43 } 44 }
20.在com.dream.service包下定义ServicePersonInfoResult数据模型。
1 package com.dream.service; 2 3 import java.util.*; 4 import com.dream.*; 5 6 public class ServicePersonInfoResult extends BaseResult { 7 private int personId = 0; 8 private String personName = null; 9 private Date personTime = null; 10 11 public int getPersonId() { 12 return this.personId; 13 } 14 15 public void setPersonId(int personId) { 16 this.personId = personId; 17 } 18 19 public String getPersonName() { 20 return this.personName; 21 } 22 23 public void setPersonName(String personName) { 24 this.personName = personName; 25 } 26 27 public Date getPersonTime() { 28 return this.personTime; 29 } 30 31 public void setPersonTime(Date personTime) { 32 this.personTime = personTime; 33 } 34 35 public ServicePersonInfoResult(ErrorCode errorCode) { 36 super(errorCode); 37 } 38 }
21.在com.dream.service包下定义ServicePersonInfo接口。
1 package com.dream.service; 2 3 public interface ServicePersonInfo { 4 ServicePersonInfoResult process(String personId); 5 }
22.在com.dream.service包下定义实现了ServicePersonInfo接口的ServicePersonInfoImpl类。
1 package com.dream.service; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.stereotype.*; 5 import com.dream.repository.*; 6 import com.dream.*; 7 8 @Service 9 public class ServicePersonInfoImpl implements ServicePersonInfo { 10 private QueryPersonById queryPersonById = null; 11 12 @Autowired 13 public void setQueryPersonById(QueryPersonById queryPersonById) { 14 this.queryPersonById = queryPersonById; 15 } 16 17 @Override 18 public ServicePersonInfoResult process(String personId) { 19 var id = Converter.toInteger(personId); 20 if (id == null) { 21 return new ServicePersonInfoResult(ErrorCode.ERROR_FATAL); 22 } 23 24 var person = this.queryPersonById.access(id); 25 if (person == null) { 26 return new ServicePersonInfoResult(ErrorCode.ERROR_CREDENTIAL); 27 } 28 29 var personInfoResult = new ServicePersonInfoResult(ErrorCode.SUCCESS); 30 personInfoResult.setPersonId(person.getPersonId()); 31 personInfoResult.setPersonName(person.getPersonName()); 32 personInfoResult.setPersonTime(person.getPersonTime()); 33 return personInfoResult; 34 } 35 }
23.在com.dream.controller包下定义ControlLogon类。
1 package com.dream.controller; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.web.bind.annotation.*; 5 import org.springframework.web.context.request.*; 6 import org.springframework.stereotype.*; 7 import com.dream.service.*; 8 9 @Controller 10 public class ControlLogon { 11 private ServiceLogon serviceLogon = null; 12 13 @Autowired 14 public void setServiceLogon(ServiceLogon serviceLogon) { 15 this.serviceLogon = serviceLogon; 16 } 17 18 @ResponseBody 19 @RequestMapping(value = "/logon", method = RequestMethod.POST) 20 public ServiceLogonResult visit(WebRequest request) { 21 var phone = request.getParameter("phone");; 22 var password = request.getParameter("password"); 23 return this.serviceLogon.process(phone, password); 24 } 25 }
24.在com.dream.controller包下定义ControlRegistry类。
1 package com.dream.controller; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.web.bind.annotation.*; 5 import org.springframework.web.context.request.*; 6 import org.springframework.stereotype.*; 7 import com.dream.service.*; 8 9 @Controller 10 public class ControlRegistry { 11 private ServiceRegistry serviceRegistry = null; 12 13 @Autowired 14 public void setServiceRegistry(ServiceRegistry serviceRegistry) { 15 this.serviceRegistry = serviceRegistry; 16 } 17 18 @ResponseBody 19 @RequestMapping(value = "/registry", method = RequestMethod.POST) 20 public BaseResult visit(WebRequest request) { 21 var name = request.getParameter("name"); 22 var phone = request.getParameter("phone"); 23 var password = request.getParameter("password"); 24 var confirm = request.getParameter("confirm"); 25 return this.serviceRegistry.process(name, phone, password, confirm); 26 } 27 }
25.在com.dream.controller包下定义ControlPersonInfo类。
1 package com.dream.controller; 2 3 import org.springframework.beans.factory.annotation.*; 4 import org.springframework.web.bind.annotation.*; 5 import org.springframework.web.context.request.*; 6 import org.springframework.stereotype.*; 7 import com.dream.service.*; 8 9 @Controller 10 public class ControlPersonInfo { 11 private ServicePersonInfo servicePersonInfo = null; 12 13 @Autowired 14 public void setServicePersonInfo(ServicePersonInfo servicePersonInfo) { 15 this.servicePersonInfo = servicePersonInfo; 16 } 17 18 @ResponseBody 19 @RequestMapping(value = "/person_info", method = RequestMethod.POST) 20 public ServicePersonInfoResult visit(WebRequest request) { 21 var personId = request.getParameter("personId"); 22 return this.servicePersonInfo.process(personId); 23 } 24 }
26.在/come-in/web/WEB-INF/目录里添加web.xml文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation=" 5 http://xmlns.jcp.org/xml/ns/javaee 6 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 7 version="4.0"> 8 9 <context-param> 10 <param-name>contextConfigLocation</param-name> 11 <param-value>/WEB-INF/config/root-config.xml</param-value> 12 </context-param> 13 <listener> 14 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 15 </listener> 16 17 <servlet> 18 <servlet-name>dispatcherServlet</servlet-name> 19 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 20 <init-param> 21 <param-name>contextConfigLocation</param-name> 22 <param-value>/WEB-INF/config/servlet-config.xml</param-value> 23 </init-param> 24 <load-on-startup>1</load-on-startup> 25 </servlet> 26 <servlet-mapping> 27 <servlet-name>dispatcherServlet</servlet-name> 28 <url-pattern>/</url-pattern> 29 </servlet-mapping> 30 </web-app>
27.在/come-in/web/WEB-INF/config/目录里添加servlet-config.xml文件。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <mvc:annotation-driven /> <mvc:default-servlet-handler /> <context:component-scan base-package="com.dream.controller" /> </beans>
28.在/come-in/web/WEB-INF/config/目录里添加root-config.xml文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.0.xsd"> 10 11 <context:component-scan base-package="com.dream.repository,com.dream.service" /> 12 <bean class="org.apache.commons.dbcp2.BasicDataSource"> 13 <property name="username" value="root" /> 14 <property name="password" value="123456" /> 15 <property name="url" value="jdbc:mysql://localhost:3306/come_in" /> 16 <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> 17 </bean> 18 19 </beans>
29.在/come-in/web/目录里添加index.html文件。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>登录</title> 5 <meta charset="UTF-8"> 6 <link rel="stylesheet" type="text/css" href="style/global.css"> 7 <link rel="stylesheet" type="text/css" href="style/index.css"> 8 </head> 9 <body> 10 <div id="logon-box"> 11 <div class="-title-box"> 12 <h1>登陆</h1> 13 </div> 14 <div id="logon-body-box"> 15 <div class="-input-item"> 16 <label id="logon-phone-hint" for="logon-phone-text">手机</label> 17 <input id="logon-phone-text" type="text" maxlength="48"> 18 </div> 19 <div class="-input-item"> 20 <label id="logon-password-hint" for="logon-password-text">密码</label> 21 <input id="logon-password-text" type="password" maxlength="48"> 22 </div> 23 <div class="-button-item"> 24 <input id="logon-button" class="-button" type="button" value="登陆"> 25 </div> 26 </div> 27 <div id="logon-foot-box"> 28 <label for="logon-registry-button">没有账号?</label> 29 <input id="logon-registry-button" type="button" value="马上注册"> 30 </div> 31 </div> 32 <div id="registry-box"> 33 <div class="-modal"></div> 34 <div id="registry-workbench-box" class="-modal-body"> 35 <div class="-title-box"> 36 <h1>注册</h1> 37 </div> 38 <div id="registry-body-box"> 39 <div class="-input-item"> 40 <label id="registry-name-hint" for="registry-name-text">名字</label> 41 <input id="registry-name-text" type="text" maxlength="48"> 42 </div> 43 <div class="-input-item"> 44 <label id="registry-phone-hint" for="registry-phone-text">手机</label> 45 <input id="registry-phone-text" type="text" maxlength="48"> 46 </div> 47 <div class="-input-item"> 48 <label id="registry-password-hint" for="registry-password-text">密码</label> 49 <input id="registry-password-text" type="password" maxlength="48"> 50 </div> 51 <div class="-input-item"> 52 <label id="registry-confirm-hint" for="registry-confirm-text">密码确认</label> 53 <input id="registry-confirm-text" type="password" maxlength="48"> 54 </div> 55 <div class="-button-item"> 56 <input id="registry-ok-button" class="-button" type="button" value="注册"> 57 <input id="registry-cancel-button" class="-button" type="button" value="取消"> 58 </div> 59 </div> 60 </div> 61 </div> 62 63 <script type="text/javascript" src="script/index.js"></script> 64 </body> 65 </html>
30.在/come-in/web/style/目录里添加global.css文件。
1 @charset "UTF-8"; 2 * { 3 margin:0; 4 padding:0; 5 } 6 html { 7 width:100%; 8 height:100%; 9 background-color:white; 10 } 11 body { 12 width:100%; 13 min-height:100%; 14 background-color:white; 15 background-repeat:no-repeat; 16 background-position:center; 17 font:14px/24px "Microsoft Yahei",微软雅黑,Arial,arial,SimSun,simsun; 18 font-weight:normal; 19 color:#333333; 20 } 21 a { 22 color:#3b5999; 23 text-decoration:none; 24 outline:none; 25 } 26 a:hover { 27 color:#699857; 28 } 29 img { 30 border-width:0; 31 } 32 input { 33 outline:none; 34 } 35 input[type=text]::-ms-clear { 36 display:none; 37 } 38 input[type=button] { 39 appearance:none; 40 -moz-appearance:none; 41 -webkit-appearance:none; 42 border-radius:0; 43 } 44 textarea { 45 resize:none; 46 outline:none; 47 } 48 strong { 49 font-style:normal; 50 font-weight:bold; 51 } 52 h1,h2,h3,h4,h5,h6 { 53 font-size:100%; 54 font-weight:bold; 55 } 56 input,button,textarea,select,optgroup,option { 57 font-family:inherit; 58 font-size:inherit; 59 font-style:inherit; 60 font-weight:inherit; 61 } 62 .-button { 63 height:40px; 64 border-width:0; 65 font-size:16px; 66 font-weight:bold; 67 line-height:40px; 68 background-color:#558543; 69 color:white; 70 cursor:pointer; 71 } 72 .-button:hover { 73 background-color:#699857; 74 } 75 .-clear:after { 76 content:"\200B"; 77 display:block; 78 height:0; 79 clear:both; 80 } 81 .-clear { 82 *zoom:1; 83 } 84 .-modal { 85 position:fixed; 86 top:0; 87 left:0; 88 right:0; 89 bottom:0; 90 opacity:0.3; 91 filter:alpha(opacity=30); 92 background-color:#333333; 93 z-index:90000000; 94 } 95 .-modal-body { 96 position:fixed; 97 background-color:#e9ebee; 98 z-index:91000000; 99 }
31.在/come-in/web/style/目录里添加index.css文件。
1 @charset "UTF-8"; 2 body { 3 position:relative; 4 } 5 #logon-box { 6 float:left; 7 width:354px; 8 height:399px; 9 margin:60px; 10 border-bottom:9px solid #3b5999; 11 background-color:#e9ebee; 12 } 13 #logon-body-box { 14 width:auto; 15 height:258px; 16 padding:18px 18px 0px; 17 } 18 #logon-button { 19 width:100%; 20 } 21 #logon-foot-box { 22 width:auto; 23 height:20px; 24 padding:16px 18px; 25 font-size:14px; 26 line-height:20px; 27 } 28 #logon-foot-box label { 29 float:left; 30 cursor:pointer; 31 } 32 #logon-foot-box input { 33 width:auto; 34 height:20px; 35 border-width:0px; 36 font-size:14px; 37 line-height:20px; 38 background-color:transparent; 39 color:#3b5999; 40 cursor:pointer; 41 } 42 #logon-foot-box input:hover { 43 color:#699857; 44 } 45 #logon-registry-button { 46 float:left; 47 } 48 #registry-box { 49 display:none; 50 } 51 #registry-workbench-box { 52 top:142px; 53 left:50%; 54 width:354px; 55 height:380px; 56 margin-left:-177px; 57 } 58 #registry-body-box { 59 width:auto; 60 height:290px; 61 padding:18px 18px 0px; 62 } 63 #registry-ok-button { 64 float:right; 65 width:254px; 66 } 67 #registry-cancel-button { 68 float:left; 69 width:58px; 70 } 71 .-title-box { 72 width:auto; 73 height:72px; 74 padding:0px 18px; 75 font-size:36px; 76 line-height:72px; 77 background-color:#3b5999; 78 color:white; 79 } 80 .-title-box h1 { 81 font-weight:normal; 82 } 83 .-input-item { 84 position:relative; 85 width:auto; 86 height:38px; 87 margin-bottom:18px; 88 border:1px solid #888888; 89 background-color:white; 90 } 91 .-input-item label { 92 position:absolute; 93 top:0px; 94 left:0px; 95 width:auto; 96 height:38px; 97 padding:0px 9px; 98 font-size:14px; 99 line-height:38px; 100 color:#888888; 101 z-index:100; 102 } 103 .-input-item input { 104 position:absolute; 105 top:0px; 106 left:0px; 107 width:298px; 108 height:38px; 109 padding:0px 9px; 110 border-width:0px; 111 font-size:14px; 112 line-height:18px; 113 background-color:transparent; 114 color:#333333; 115 z-index:110; 116 } 117 .-button-item { 118 position:relative; 119 width:auto; 120 height:40px; 121 }
32.在/come-in/web/script/目录里添加index.js文件。
1 window.onload = function() { 2 let logonPhoneText = document.getElementById("logon-phone-text"); 3 let logonPasswordText = document.getElementById("logon-password-text"); 4 let logonButton = document.getElementById("logon-button"); 5 let logonRegistryButton = document.getElementById("logon-registry-button"); 6 let registryNameText = document.getElementById("registry-name-text"); 7 let registryPhoneText = document.getElementById("registry-phone-text"); 8 let registryPasswordText = document.getElementById("registry-password-text"); 9 let registryConfirmText = document.getElementById("registry-confirm-text"); 10 let registryOkButton = document.getElementById("registry-ok-button"); 11 let registryCancelButton = document.getElementById("registry-cancel-button"); 12 13 logonPhoneText.onfocus = onLogonPhoneTextFocus; 14 logonPhoneText.onblur = onLogonPhoneTextBlur; 15 logonPasswordText.onfocus = onLogonPasswordTextFocus; 16 logonPasswordText.onblur = onLogonPasswordTextBlur; 17 logonButton.onclick = onLogonButtonClick; 18 logonRegistryButton.onclick = onLogonRegistryButtonClick; 19 registryNameText.onfocus = onRegistryNameTextFocus; 20 registryNameText.onblur = onRegistryNameTextBlur; 21 registryPhoneText.onfocus = onRegistryPhoneTextFocus; 22 registryPhoneText.onblur = onRegistryPhoneTextBlur; 23 registryPasswordText.onfocus = onRegistryPasswordTextFocus; 24 registryPasswordText.onblur = onRegistryPasswordTextBlur; 25 registryConfirmText.onfocus = onRegistryConfirmTextFocus; 26 registryConfirmText.onblur = onRegistryConfirmTextBlur; 27 registryOkButton.onclick = onRegistryOkButtonClick; 28 registryCancelButton.onclick = onRegistryCancelButtonClick; 29 } 30 31 function onLogonPhoneTextFocus() { 32 let logonPhoneHint = document.getElementById("logon-phone-hint"); 33 logonPhoneHint.style.display = "none"; 34 } 35 36 function onLogonPhoneTextBlur() { 37 let logonPhoneText = document.getElementById("logon-phone-text"); 38 let logonPhoneHint = document.getElementById("logon-phone-hint"); 39 logonPhoneHint.style.display = (logonPhoneText.value.length === 0 ? "block" : "none"); 40 } 41 42 function onLogonPasswordTextFocus() { 43 let logonPasswordHint = document.getElementById("logon-password-hint"); 44 logonPasswordHint.style.display = "none"; 45 } 46 47 function onLogonPasswordTextBlur() { 48 let logonPasswordText = document.getElementById("logon-password-text"); 49 let logonPasswordHint = document.getElementById("logon-password-hint"); 50 logonPasswordHint.style.display = (logonPasswordText.value.length === 0 ? "block" : "none"); 51 } 52 53 function onLogonButtonClick() { 54 if(validateLogon()) { 55 let phoneText = document.getElementById("logon-phone-text"); 56 let passwordText = document.getElementById("logon-password-text"); 57 let phone = eraseSpace(phoneText.value.trim()); 58 let password = passwordText.value; 59 requestLogon(phone, password); 60 } 61 } 62 63 function onLogonRegistryButtonClick() { 64 let registryBox = document.getElementById("registry-box"); 65 registryBox.style.display = "block"; 66 } 67 68 function onRegistryNameTextFocus() { 69 let registryNameHint = document.getElementById("registry-name-hint"); 70 registryNameHint.style.display = "none"; 71 } 72 73 function onRegistryNameTextBlur() { 74 let registryNameText = document.getElementById("registry-name-text"); 75 let registryNameHint = document.getElementById("registry-name-hint"); 76 registryNameHint.style.display = (registryNameText.value.length === 0 ? "block" : "none"); 77 } 78 79 function onRegistryPhoneTextFocus() { 80 let registryPhoneHint = document.getElementById("registry-phone-hint"); 81 registryPhoneHint.style.display = "none"; 82 } 83 84 function onRegistryPhoneTextBlur() { 85 let registryPhoneText = document.getElementById("registry-phone-text"); 86 let registryPhoneHint = document.getElementById("registry-phone-hint"); 87 registryPhoneHint.style.display = (registryPhoneText.value.length === 0 ? "block" : "none"); 88 } 89 90 function onRegistryPasswordTextFocus() { 91 let registryPasswordHint = document.getElementById("registry-password-hint"); 92 registryPasswordHint.style.display = "none"; 93 } 94 95 function onRegistryPasswordTextBlur() { 96 let registryPasswordText = document.getElementById("registry-password-text"); 97 let registryPasswordHint = document.getElementById("registry-password-hint"); 98 registryPasswordHint.style.display = (registryPasswordText.value.length === 0 ? "block" : "none"); 99 } 100 101 function onRegistryConfirmTextFocus() { 102 let registryConfirmHint = document.getElementById("registry-confirm-hint"); 103 registryConfirmHint.style.display = "none"; 104 } 105 106 function onRegistryConfirmTextBlur() { 107 let registryConfirmText = document.getElementById("registry-confirm-text"); 108 let registryConfirmHint = document.getElementById("registry-confirm-hint"); 109 registryConfirmHint.style.display = (registryConfirmText.value.length === 0 ? "block" : "none"); 110 } 111 112 function onRegistryOkButtonClick() { 113 if(validateRegistry()) { 114 let nameText = document.getElementById("registry-name-text"); 115 let phoneText = document.getElementById("registry-phone-text"); 116 let passwordText = document.getElementById("registry-password-text"); 117 let confirmText = document.getElementById("registry-confirm-text"); 118 let name = nameText.value.trim(); 119 let phone = eraseSpace(phoneText.value.trim()); 120 let password = passwordText.value; 121 let confirm = confirmText.value; 122 requestRegistry(name, phone, password, confirm); 123 } 124 } 125 126 function onRegistryCancelButtonClick() { 127 let registryBox = document.getElementById("registry-box"); 128 registryBox.style.display = "none"; 129 } 130 131 function validateLogon() { 132 let phoneText = document.getElementById("logon-phone-text"); 133 let phone = eraseSpace(phoneText.value.trim()); 134 if (phone.length === 0) { 135 showMessage("请输入手机号码!", "知道了", null); 136 return false; 137 } 138 if (!isPhoneValid(phone)) { 139 showMessage("手机号码输错了!", "知道了", null); 140 return false; 141 } 142 143 let passwordText = document.getElementById("logon-password-text"); 144 let password = passwordText.value; 145 if (password.length === 0) { 146 showMessage("请输入密码!", "知道了", null); 147 return false; 148 } 149 if (password.length < 6) { 150 showMessage("密码输错了!", "知道了", null); 151 return false; 152 } 153 return true; 154 } 155 156 function validateRegistry() { 157 let nameText = document.getElementById("registry-name-text"); 158 let name = nameText.value.trim(); 159 if (name.length === 0) { 160 showMessage("名字需要1-12个字符!", "知道了", null); 161 return false; 162 } 163 if (name.length > 12) { 164 showMessage("名字不能多于12个字符!", "知道了", null); 165 return false; 166 } 167 168 let phoneText = document.getElementById("registry-phone-text"); 169 let phone = eraseSpace(phoneText.value.trim()); 170 if (phone.length === 0) { 171 showMessage("请输入您的手机号码!", "知道了", null); 172 return false; 173 } 174 if (!isPhoneValid(phone)) { 175 showMessage("请输入正确的手机号码!", "知道了", null); 176 return false; 177 } 178 179 let passwordText = document.getElementById("registry-password-text"); 180 let password = passwordText.value; 181 if (password.length === 0 || password.length < 6) { 182 showMessage("密码不能少于6个字符!", "知道了", null); 183 return false; 184 } 185 186 let confirmText = document.getElementById("registry-confirm-text"); 187 let confirm = confirmText.value; 188 if (confirm.length === 0) { 189 showMessage("请输入密码确认!", "知道了", null); 190 return false; 191 } 192 if (confirm !== password) { 193 showMessage("密码确认需与密码相同!", "知道了", null); 194 return false; 195 } 196 197 return true; 198 } 199 200 function requestLogon(phone, password) { 201 let requestData = "phone=" + encodeURIComponent(phone) 202 + "&password=" + encodeURIComponent(password); 203 let request = new XMLHttpRequest(); 204 request.onload = requestLogonHandler; 205 request.open("POST", "logon"); 206 request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 207 request.send(requestData); 208 } 209 210 function requestLogonHandler() { 211 if(this.status == 200 && this.responseText != null) { 212 let responseJson = JSON.parse(this.responseText); 213 if(responseJson && responseJson.errorCode === "SUCCESS") { 214 window.location.replace("welcome.html?personId=" + responseJson.personId); 215 } else if (responseJson && responseJson.errorCode === "ERROR_CREDENTIAL") { 216 showMessage("手机或密码输错了,请重新输入!", "知道了", null); 217 } else { 218 showMessage("登录失败。页面发生了严重错误,请重试!", "知道了", null); 219 } 220 } 221 } 222 223 function requestRegistry(name, phone, password, confirm) { 224 let requestData = "name=" + encodeURIComponent(name) 225 + "&phone=" + encodeURIComponent(phone) 226 + "&password=" + encodeURIComponent(password) 227 + "&confirm=" + encodeURIComponent(confirm); 228 let request = new XMLHttpRequest(); 229 request.onload = requestRegistryHandler; 230 request.open("POST", "registry"); 231 request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 232 request.send(requestData); 233 } 234 235 function requestRegistryHandler() { 236 if(this.status == 200 && this.responseText != null) { 237 let responseJson = JSON.parse(this.responseText); 238 if(responseJson && responseJson.errorCode === "SUCCESS") { 239 let registryBox = document.getElementById("registry-box"); 240 registryBox.style.display = "none"; 241 showMessage("注册成功!", "知道了", null); 242 } else if (responseJson && responseJson.errorCode === "ERROR_DUPLICATE") { 243 showMessage("手机号码已被注册过,请用其它号码!", "知道了", null); 244 } else { 245 showMessage("注册失败。页面发生了严重错误,请重试!", "知道了", null); 246 } 247 } 248 } 249 250 function isPhoneValid(value) { 251 return /^1[0-9]{10}$/.test(value); 252 } 253 254 function eraseSpace(value) { 255 return value.replace(/ /gi, ""); 256 } 257 258 function showMessage(msg, okButtontext, okButtonAction) { 259 let messageBox = document.createElement("div"); 260 messageBox.id = "message-box"; 261 messageBox.innerHTML = "" 262 + "<div class='-modal' style='z-index:900000000'></div>" 263 + "<div class='-modal-body' style='top:50%;left:50%;width:492px;height:40px;padding:6px;margin:-58px 0px 0px -255px;border-left:6px solid #3b5999;border-radius:3px 0px 0px 3px;line-height:40px;z-index:910000000;'>" 264 + " <span style='float:left;width:398px;height:40px;'>" + msg + "</span>" 265 + " <input id='message-box-ok-button' type='button' value='" + okButtontext + "' style='float:right;width:88px;height:40px;border-width:0px;font-size:16px;font-weight:bold;line-height:40px;background-color:#558543;color:white;cursor:pointer;'>" 266 + "</div>"; 267 document.body.appendChild(messageBox); 268 269 let messageBoxOkButton = document.getElementById("message-box-ok-button"); 270 messageBoxOkButton.onmouseenter = function() { 271 messageBoxOkButton.style.background = "#699857"; 272 }; 273 messageBoxOkButton.onmouseleave = function() { 274 messageBoxOkButton.style.background = "#558543"; 275 }; 276 messageBoxOkButton.onclick = function() { 277 document.body.removeChild(messageBox); 278 if(okButtonAction) { 279 okButtonAction(); 280 } 281 }; 282 }
33.在/come-in/web/目录里添加welcome.html文件。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>欢迎</title> 5 <meta charset="UTF-8"> 6 <link rel="stylesheet" type="text/css" href="style/global.css"> 7 <link rel="stylesheet" type="text/css" href="style/welcome.css"> 8 </head> 9 <body> 10 <div id="person-info-box"></div> 11 12 <script type="text/javascript" src="script/welcome.js"></script> 13 </body> 14 </html>
34.在/come-in/web/style/目录里添加welcome.css文件。
1 #person-info-box p { 2 margin:12px; 3 font-size: 24px; 4 font-weight: bold; 5 }
35.在/come-in/web/script/目录里添加welcome.js文件。
1 window.onload = function() { 2 let requestData = "personId=" + encodeURIComponent(getParam("personId")); 3 let request = new XMLHttpRequest(); 4 request.onload = requestPersonInfoHandler; 5 request.open("POST", "person_info"); 6 request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 7 request.send(requestData); 8 } 9 10 function requestPersonInfoHandler() { 11 if(this.status == 200 && this.responseText != null) { 12 let responseJson = JSON.parse(this.responseText); 13 if(responseJson && responseJson.errorCode === "SUCCESS") { 14 let personInfoBox = document.getElementById("person-info-box"); 15 personInfoBox.innerHTML = "<p>您好," + responseJson.personName + "!</p>"; 16 } else { 17 let personInfoBox = document.getElementById("person-info-box"); 18 personInfoBox.innerHTML = "<p>页面发生了严重错误,请重新登录!</p>"; 19 } 20 } 21 } 22 23 function getParam(paramName) { 24 let query = window.location.search.substring(1); 25 let paramArray = query.split("&"); 26 for (let i = 0; i < paramArray.length; i++) { 27 let paramPair = paramArray[i].split("="); 28 if(paramPair[0] === paramName) { 29 return paramPair[1]; 30 } 31 } 32 return null; 33 }
完成!
当然,这个网站尚有很多缺陷。比如没有进行异常处理,导致我们的应用程序非常脆弱;比如没有进行编码处理,导致用户使用中文进行注册的话,显示的是一堆乱码。但是,所有这些缺陷并不影响我们整个网站基础功能的实现,也不影响我们希望通过这个小项目加深对Spring框架的理解的初衷。还有,随着学习的深入。大家自然而然的就知道怎么补上这些缺陷了。
https://github.com/Evan-I/Open-Spring
来源:https://www.cnblogs.com/evanlin/p/15552739.html