├── .gitignore ├── README.md ├── pom.xml ├── sql └── schema.sql └── src ├── main ├── java │ └── cn │ │ └── mccreefei │ │ ├── dao │ │ ├── LoginInfoDAO.java │ │ ├── MessageRecordDAO.java │ │ └── UserDAO.java │ │ ├── enums │ │ ├── LoginTypeEnum.java │ │ └── MessageTypeEnum.java │ │ ├── model │ │ ├── LoginInfoDo.java │ │ ├── Message.java │ │ ├── MessageRecordDo.java │ │ ├── ParticipantRepository.java │ │ ├── ReplyLoginMessage.java │ │ ├── ReplyRegistMessage.java │ │ └── User.java │ │ ├── service │ │ ├── UserService.java │ │ └── impl │ │ │ └── UserServiceImpl.java │ │ └── web │ │ ├── LoginController.java │ │ ├── MessageController.java │ │ └── websocket │ │ ├── WebSocketConfig.java │ │ └── WebSocketDisconnectHandler.java ├── resources │ ├── log4j2.xml │ ├── map │ │ ├── LoginInfoMapper.xml │ │ ├── MessageRecordMapper.xml │ │ └── userMapper.xml │ ├── mybatis-config.xml │ ├── spring │ │ ├── spring-dao.xml │ │ └── spring-web.xml │ └── system-config.properties └── webapp │ ├── WEB-INF │ ├── jsp │ │ ├── chatroom.jsp │ │ └── index.jsp │ └── web.xml │ └── resources │ ├── css │ ├── login.css │ └── main.css │ ├── image │ ├── 1.jpg │ └── favicon.ico │ ├── js │ ├── chatroom.js │ └── login.js │ ├── media │ ├── emoji │ │ ├── 1.gif │ │ ├── 10.gif │ │ ├── 11.gif │ │ ├── 12.gif │ │ ├── 13.gif │ │ ├── 14.gif │ │ ├── 15.gif │ │ ├── 16.gif │ │ ├── 17.gif │ │ ├── 18.gif │ │ ├── 19.gif │ │ ├── 2.gif │ │ ├── 20.gif │ │ ├── 21.gif │ │ ├── 22.gif │ │ ├── 23.gif │ │ ├── 24.gif │ │ ├── 25.gif │ │ ├── 26.gif │ │ ├── 27.gif │ │ ├── 28.gif │ │ ├── 29.gif │ │ ├── 3.gif │ │ ├── 30.gif │ │ ├── 31.gif │ │ ├── 32.gif │ │ ├── 33.gif │ │ ├── 34.gif │ │ ├── 35.gif │ │ ├── 36.gif │ │ ├── 37.gif │ │ ├── 38.gif │ │ ├── 39.gif │ │ ├── 4.gif │ │ ├── 40.gif │ │ ├── 41.gif │ │ ├── 42.gif │ │ ├── 43.gif │ │ ├── 44.gif │ │ ├── 45.gif │ │ ├── 46.gif │ │ ├── 47.gif │ │ ├── 48.gif │ │ ├── 49.gif │ │ ├── 5.gif │ │ ├── 50.gif │ │ ├── 51.gif │ │ ├── 52.gif │ │ ├── 53.gif │ │ ├── 54.gif │ │ ├── 55.gif │ │ ├── 56.gif │ │ ├── 57.gif │ │ ├── 58.gif │ │ ├── 59.gif │ │ ├── 6.gif │ │ ├── 60.gif │ │ ├── 61.gif │ │ ├── 62.gif │ │ ├── 63.gif │ │ ├── 64.gif │ │ ├── 65.gif │ │ ├── 66.gif │ │ ├── 67.gif │ │ ├── 68.gif │ │ ├── 69.gif │ │ ├── 7.gif │ │ ├── 8.gif │ │ └── 9.gif │ └── image │ │ └── chris_619283.jpg │ └── plugin │ └── sweetalert │ ├── sweetalert.css │ └── sweetalert.min.js └── test └── java └── cn └── mccreefei └── dao └── UserDAOTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyChat 2 | 一个基于SSM+Websocket的实时在线聊天室项目 3 | 4 | ## 功能展示 5 | ![功能展示](https://i.loli.net/2019/01/13/5c3b3d59c4c9b.gif) 6 | ## 本地部署 7 | - 将```sql/schema.sql```导入本地mysql,修改```resources/system-config.properties```中mysql用户名与密码。 8 | - 使用maven jetty插件运行本项目,配置如下 9 | ![easychat.png](https://i.loli.net/2019/06/05/5cf7798fd5d8c71326.png) 10 | - Enjoy! 11 | ## 博客地址 12 | [博客地址](https://www.mccreefei.cn/post/easychat/) 13 | 14 | ## 试用 15 | >>> 随缘链接(可能遭遇服务器到期崩溃等不可抗因素) 16 | [www.mccreefei.cn:8080](http://www.mccreefei.cn:8080) 17 | 18 | ## 联系 19 | Email: mccreefei@foxmail.com 20 | 21 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | cn.mccreefei 5 | easy-chat 6 | war 7 | 1.0-SNAPSHOT 8 | easy-chat Maven Webapp 9 | http://maven.apache.org 10 | 11 | 4.3.7.RELEASE 12 | 13 | 14 | 15 | 16 | junit 17 | junit 18 | 4.12 19 | test 20 | 21 | 22 | 23 | org.springframework 24 | spring-test 25 | ${spring.version} 26 | 27 | 28 | 29 | 30 | mysql 31 | mysql-connector-java 32 | 5.1.6 33 | 34 | 35 | 36 | org.mybatis 37 | mybatis 38 | 3.4.4 39 | 40 | 41 | 42 | org.mybatis 43 | mybatis-spring 44 | 1.3.1 45 | 46 | 47 | 48 | org.springframework 49 | spring-jdbc 50 | ${spring.version} 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | com.alibaba 62 | druid 63 | 1.1.9 64 | 65 | 66 | 67 | 68 | taglibs 69 | standard 70 | 1.1.2 71 | 72 | 73 | 74 | javax.servlet 75 | javax.servlet-api 76 | 3.0.1 77 | provided 78 | 79 | 80 | 81 | javax.servlet.jsp.jstl 82 | jstl-api 83 | 1.2 84 | 85 | 86 | javax.servlet 87 | servlet-api 88 | 89 | 90 | javax.servlet.jsp 91 | jsp-api 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.slf4j 99 | slf4j-api 100 | 1.7.25 101 | 102 | 103 | org.apache.logging.log4j 104 | log4j-slf4j-impl 105 | 2.8.1 106 | 107 | 108 | org.apache.logging.log4j 109 | log4j-api 110 | 2.8.2 111 | 112 | 113 | org.apache.logging.log4j 114 | log4j-core 115 | 2.8.2 116 | 117 | 118 | 119 | 120 | com.fasterxml.jackson.core 121 | jackson-databind 122 | 2.8.8 123 | 124 | 125 | 126 | com.fasterxml.jackson.core 127 | jackson-core 128 | 2.8.8 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | org.springframework 137 | spring-context 138 | ${spring.version} 139 | 140 | 141 | 142 | org.springframework 143 | spring-core 144 | ${spring.version} 145 | 146 | 147 | 148 | org.springframework 149 | spring-beans 150 | ${spring.version} 151 | 152 | 153 | 154 | 155 | org.springframework 156 | spring-webmvc 157 | ${spring.version} 158 | 159 | 160 | 161 | org.springframework 162 | spring-web 163 | ${spring.version} 164 | 165 | 166 | 167 | 168 | org.springframework 169 | spring-messaging 170 | ${spring.version} 171 | 172 | 173 | 174 | org.springframework 175 | spring-websocket 176 | ${spring.version} 177 | 178 | 179 | 180 | 181 | commons-fileupload 182 | commons-fileupload 183 | 1.3.2 184 | 185 | 186 | 187 | commons-io 188 | commons-io 189 | 2.4 190 | 191 | 192 | 193 | 194 | 195 | easy-chat 196 | 197 | 198 | org.eclipse.jetty 199 | jetty-maven-plugin 200 | 9.3.7.v20160115 201 | 202 | 203 | 8080 204 | localhost 205 | 206 | 1 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /sql/schema.sql: -------------------------------------------------------------------------------- 1 | #创建数据库 2 | CREATE database easychat; 3 | 4 | #创建用户表 5 | CREATE TABLE user( 6 | id INT NOT NULL PRIMARY KEY auto_increment comment'用户id', 7 | name VARCHAR(100) comment'用户名', 8 | password VARCHAR(100) comment'用户密码' 9 | )ENGINE = innoDB CHARSET = utf8; 10 | 11 | #登陆登出信息表 12 | CREATE TABLE `easychat`.`login_info` ( 13 | `id` INT NOT NULL AUTO_INCREMENT, 14 | `user_id` INT NULL, 15 | `user_name` VARCHAR(45) NULL, 16 | `status` TINYINT NULL COMMENT'1.上线,2.下线', 17 | `create_time` DATETIME NULL, 18 | PRIMARY KEY (`id`)) default charset = utf8; 19 | 20 | #聊天内容表 21 | CREATE TABLE `easychat`.`message_record` ( 22 | `id` INT NOT NULL AUTO_INCREMENT, 23 | `user_id` INT NULL, 24 | `user_name` VARCHAR(45) NULL, 25 | `message_type` TINYINT NULL COMMENT'1.文本, 2.图片', 26 | `content` VARCHAR(256) NULL, 27 | `create_time` VARCHAR(45) NULL, 28 | PRIMARY KEY (`id`))default charset = utf8; -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/dao/LoginInfoDAO.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.dao; 2 | 3 | import cn.mccreefei.model.LoginInfoDo; 4 | 5 | /** 6 | * @author MccreeFei 7 | * @create 2018-04-28 下午1:36 8 | */ 9 | public interface LoginInfoDAO { 10 | int addLoginInfo(LoginInfoDo loginInfoDo); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/dao/MessageRecordDAO.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.dao; 2 | 3 | import cn.mccreefei.model.MessageRecordDo; 4 | 5 | /** 6 | * @author MccreeFei 7 | * @create 2018-04-28 下午1:37 8 | */ 9 | public interface MessageRecordDAO { 10 | int addMessageRecord(MessageRecordDo messageRecordDo); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/dao/UserDAO.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.dao; 2 | 3 | import cn.mccreefei.model.User; 4 | import org.apache.ibatis.annotations.Param; 5 | 6 | /** 7 | * 用户dao接口 8 | */ 9 | public interface UserDAO { 10 | /** 11 | * 以用户名和密码查询用户 12 | * @param name 13 | * @param password 14 | * @return 存在返回该用户对象,不存在返回null 15 | */ 16 | User queryUser(@Param("name") String name,@Param("password") String password); 17 | 18 | /** 19 | * 以用户名查询用户 20 | * @param name 21 | * @return 存在该用户名返回用户对象,否则返回null 22 | */ 23 | User queryUserByName(String name); 24 | 25 | /** 26 | * 插入一位用户 27 | * @param name 28 | * @param password 29 | */ 30 | void insertUser(@Param("name") String name,@Param("password") String password); 31 | 32 | /** 33 | * 根据用户名获取用户信息 34 | * @param name 35 | * @return 36 | */ 37 | User getUserByName(@Param("name") String name); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/enums/LoginTypeEnum.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.enums; 2 | 3 | /** 4 | * @author MccreeFei 5 | * @create 2018-04-28 下午1:49 6 | */ 7 | public enum LoginTypeEnum { 8 | LOGIN(1, "上线"), 9 | LOGOUT(2, "下线"); 10 | private int code; 11 | private String desc; 12 | 13 | LoginTypeEnum(int code, String desc) { 14 | this.code = code; 15 | this.desc = desc; 16 | } 17 | 18 | public int getCode() { 19 | return code; 20 | } 21 | 22 | public String getDesc() { 23 | return desc; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/enums/MessageTypeEnum.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.enums; 2 | 3 | /** 4 | * @author MccreeFei 5 | * @create 2018-04-28 下午1:30 6 | */ 7 | public enum MessageTypeEnum { 8 | TEXT(1, "text"), 9 | IMAGE(2, "image"); 10 | private int code; 11 | private String desc; 12 | 13 | MessageTypeEnum(int code, String desc) { 14 | this.code = code; 15 | this.desc = desc; 16 | } 17 | 18 | public int getCode() { 19 | return code; 20 | } 21 | 22 | public String getDesc() { 23 | return desc; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/LoginInfoDo.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author MccreeFei 7 | * @create 2018-04-28 下午1:32 8 | */ 9 | public class LoginInfoDo { 10 | private Integer id; 11 | private Integer userId; 12 | private String userName; 13 | private Integer status; 14 | private Date createTime; 15 | 16 | public LoginInfoDo() { 17 | } 18 | 19 | public LoginInfoDo(Integer id, Integer userId, String userName, Integer status, Date createTime) { 20 | this.id = id; 21 | this.userId = userId; 22 | this.userName = userName; 23 | this.status = status; 24 | this.createTime = createTime; 25 | } 26 | 27 | public static LoginInfoBuilder builder(){ 28 | return new LoginInfoBuilder(); 29 | } 30 | 31 | public static class LoginInfoBuilder{ 32 | private Integer id; 33 | private Integer userId; 34 | private String userName; 35 | private Integer status; 36 | private Date createTime; 37 | 38 | public LoginInfoBuilder id(Integer id) { 39 | this.id = id; 40 | return this; 41 | } 42 | 43 | public LoginInfoBuilder userId(Integer userId) { 44 | this.userId = userId; 45 | return this; 46 | } 47 | 48 | public LoginInfoBuilder userName(String userName) { 49 | this.userName = userName; 50 | return this; 51 | } 52 | 53 | public LoginInfoBuilder status(Integer status) { 54 | this.status = status; 55 | return this; 56 | } 57 | 58 | public LoginInfoBuilder createTime(Date createTime) { 59 | this.createTime = createTime; 60 | return this; 61 | } 62 | 63 | public LoginInfoDo build(){ 64 | return new LoginInfoDo(id, userId, userName, status, createTime); 65 | } 66 | } 67 | 68 | public Integer getId() { 69 | return id; 70 | } 71 | 72 | public void setId(Integer id) { 73 | this.id = id; 74 | } 75 | 76 | public Integer getUserId() { 77 | return userId; 78 | } 79 | 80 | public void setUserId(Integer userId) { 81 | this.userId = userId; 82 | } 83 | 84 | public String getUserName() { 85 | return userName; 86 | } 87 | 88 | public void setUserName(String userName) { 89 | this.userName = userName; 90 | } 91 | 92 | public Integer getStatus() { 93 | return status; 94 | } 95 | 96 | public void setStatus(Integer status) { 97 | this.status = status; 98 | } 99 | 100 | public Date getCreateTime() { 101 | return createTime; 102 | } 103 | 104 | public void setCreateTime(Date createTime) { 105 | this.createTime = createTime; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/Message.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * 用户发送消息的实体 7 | */ 8 | public class Message { 9 | private String userName; //发送者 10 | private Date sendDate; //发送日期 11 | private String content; //发送内容 12 | private String messageType;//发送消息类型(“text”文本,“image”图片) 13 | 14 | public String getMessageType() { 15 | return messageType; 16 | } 17 | 18 | public void setMessageType(String messageType) { 19 | this.messageType = messageType; 20 | } 21 | 22 | public String getUserName() { 23 | return userName; 24 | } 25 | 26 | public void setUserName(String userName) { 27 | this.userName = userName; 28 | } 29 | 30 | public Date getSendDate() { 31 | return sendDate; 32 | } 33 | 34 | public void setSendDate(Date sendDate) { 35 | this.sendDate = sendDate; 36 | } 37 | 38 | public String getContent() { 39 | return content; 40 | } 41 | 42 | public void setContent(String content) { 43 | this.content = content; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Message{" + 49 | "userName='" + userName + '\'' + 50 | ", sendDate=" + sendDate + 51 | ", content='" + content + '\'' + 52 | ", messageType='" + messageType + '\'' + 53 | '}'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/MessageRecordDo.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author MccreeFei 7 | * @create 2018-04-28 下午1:35 8 | */ 9 | public class MessageRecordDo { 10 | private Integer id; 11 | private Integer userId; 12 | private String userName; 13 | private Integer messageType; 14 | private String content; 15 | private Date createTime; 16 | 17 | public MessageRecordDo() { 18 | } 19 | 20 | public MessageRecordDo(Integer id, Integer userId, String userName, Integer messageType, String content, Date createTime) { 21 | this.id = id; 22 | this.userId = userId; 23 | this.userName = userName; 24 | this.messageType = messageType; 25 | this.content = content; 26 | this.createTime = createTime; 27 | } 28 | 29 | public static MessageRecordBuilder messageRecordBuilder(){ 30 | return new MessageRecordBuilder(); 31 | } 32 | 33 | public static class MessageRecordBuilder{ 34 | private Integer id; 35 | private Integer userId; 36 | private String userName; 37 | private Integer messageType; 38 | private String content; 39 | private Date createTime; 40 | 41 | public MessageRecordBuilder id(Integer id) { 42 | this.id = id; 43 | return this; 44 | } 45 | 46 | public MessageRecordBuilder userId(Integer userId) { 47 | this.userId = userId; 48 | return this; 49 | } 50 | 51 | public MessageRecordBuilder userName(String userName) { 52 | this.userName = userName; 53 | return this; 54 | } 55 | 56 | public MessageRecordBuilder messageType(Integer messageType) { 57 | this.messageType = messageType; 58 | return this; 59 | } 60 | 61 | public MessageRecordBuilder content(String content) { 62 | this.content = content; 63 | return this; 64 | } 65 | 66 | public MessageRecordBuilder createTime(Date createTime) { 67 | this.createTime = createTime; 68 | return this; 69 | } 70 | 71 | public MessageRecordDo build(){ 72 | return new MessageRecordDo(id, userId, userName, messageType, content, createTime); 73 | } 74 | } 75 | 76 | public Integer getId() { 77 | return id; 78 | } 79 | 80 | public void setId(Integer id) { 81 | this.id = id; 82 | } 83 | 84 | public Integer getUserId() { 85 | return userId; 86 | } 87 | 88 | public void setUserId(Integer userId) { 89 | this.userId = userId; 90 | } 91 | 92 | public String getUserName() { 93 | return userName; 94 | } 95 | 96 | public void setUserName(String userName) { 97 | this.userName = userName; 98 | } 99 | 100 | public Integer getMessageType() { 101 | return messageType; 102 | } 103 | 104 | public void setMessageType(Integer messageType) { 105 | this.messageType = messageType; 106 | } 107 | 108 | public String getContent() { 109 | return content; 110 | } 111 | 112 | public void setContent(String content) { 113 | this.content = content; 114 | } 115 | 116 | public Date getCreateTime() { 117 | return createTime; 118 | } 119 | 120 | public void setCreateTime(Date createTime) { 121 | this.createTime = createTime; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/ParticipantRepository.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.atomic.AtomicLong; 8 | 9 | /** 10 | *在线用户仓库,存储在线用户 11 | */ 12 | @Component 13 | public class ParticipantRepository { 14 | private Map activeSessions = new ConcurrentHashMap(); //在线用户map,键:用户名称,值:用户对象 15 | public Map getActiveSessions() { 16 | return activeSessions; 17 | } 18 | 19 | public void setActiveSessions(Map activeSessions) { 20 | this.activeSessions = activeSessions; 21 | } 22 | 23 | public void add(String name, User user){ 24 | activeSessions.put(name, user); 25 | 26 | } 27 | 28 | public User remove(String name){ 29 | return activeSessions.remove(name); 30 | } 31 | 32 | public boolean containsUserName(String name){ 33 | return activeSessions.containsKey(name); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/ReplyLoginMessage.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | /** 4 | * 反馈前端ajax登录的信息实体 5 | */ 6 | public class ReplyLoginMessage { 7 | public static final Integer USER_NAME_NOT_EXIST = 1; //当前登录的用户名尚未注册 8 | public static final Integer USER_PASSWORD_WRONG = 2; //登录密码错误 9 | public static final Integer USER_NAME_OR_PASSWORD_NULL = 3; //用户姓名或密码未填写 10 | private boolean successed; //登录是否成功 11 | private Integer errStatus; //错误原因 12 | 13 | public ReplyLoginMessage(boolean successed) { 14 | this.successed = successed; 15 | } 16 | 17 | public ReplyLoginMessage(boolean successed, Integer errStatus) { 18 | this.successed = successed; 19 | this.errStatus = errStatus; 20 | } 21 | 22 | public boolean isSuccessed() { 23 | return successed; 24 | } 25 | 26 | public void setSuccessed(boolean successed) { 27 | this.successed = successed; 28 | } 29 | 30 | public Integer getErrStatus() { 31 | return errStatus; 32 | } 33 | 34 | public void setErrStatus(Integer errStatus) { 35 | this.errStatus = errStatus; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/ReplyRegistMessage.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | /** 4 | * 反馈前端ajax注册的消息实体 5 | */ 6 | public class ReplyRegistMessage { 7 | public static final Integer USER_NAME_EXIST = 1; //注册名已经存在 8 | private boolean successed; //是否注册成功 9 | private Integer errStatus; //错误原因 10 | 11 | public ReplyRegistMessage(boolean isSuccessed) { 12 | this.successed = isSuccessed; 13 | } 14 | 15 | public ReplyRegistMessage(boolean isSuccessed, Integer errStatus) { 16 | this.successed = isSuccessed; 17 | this.errStatus = errStatus; 18 | } 19 | 20 | public boolean isSuccessed() { 21 | return successed; 22 | } 23 | 24 | public void setSuccessed(boolean successed) { 25 | successed = successed; 26 | } 27 | 28 | public Integer getErrStatus() { 29 | return errStatus; 30 | } 31 | 32 | public void setErrStatus(Integer errStatus) { 33 | this.errStatus = errStatus; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/model/User.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * 用户实体类 7 | */ 8 | public class User { 9 | private int id; 10 | private String name; 11 | private String password; 12 | 13 | private Date loginDate; 14 | private Date logoutDate; 15 | 16 | public int getId() { 17 | return id; 18 | } 19 | 20 | public void setId(int id) { 21 | this.id = id; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | public String getPassword() { 33 | return password; 34 | } 35 | 36 | public void setPassword(String password) { 37 | this.password = password; 38 | } 39 | 40 | public Date getLoginDate() { 41 | return loginDate; 42 | } 43 | 44 | public void setLoginDate(Date loginDate) { 45 | this.loginDate = loginDate; 46 | } 47 | 48 | public Date getLogoutDate() { 49 | return logoutDate; 50 | } 51 | 52 | public void setLogoutDate(Date logoutDate) { 53 | this.logoutDate = logoutDate; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "User{" + 59 | "id=" + id + 60 | ", name='" + name + '\'' + 61 | ", password='" + password + '\'' + 62 | ", loginDate=" + loginDate + 63 | ", logoutDate=" + logoutDate + 64 | '}'; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/service/UserService.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.service; 2 | 3 | import cn.mccreefei.model.LoginInfoDo; 4 | import cn.mccreefei.model.MessageRecordDo; 5 | import cn.mccreefei.model.User; 6 | 7 | /** 8 | * 用户service接口 9 | */ 10 | public interface UserService { 11 | 12 | /** 13 | * 验证用户密码 14 | * @param name 15 | * @param password 16 | * @return 正确返回该用户对象,否则返回空 17 | */ 18 | public User validateUserPassword(String name, String password); 19 | 20 | /** 21 | * 该用户是否已经注册 22 | * @param name 23 | * @return 24 | */ 25 | public boolean isExistUser(String name); 26 | 27 | /** 28 | * 插入一名用户 29 | * @param name 30 | * @param password 31 | */ 32 | public void insertUser(String name, String password); 33 | 34 | public void addUserLoginInfo(LoginInfoDo loginInfoDo); 35 | 36 | public void addUserMessageRecord(MessageRecordDo messageRecordDo); 37 | 38 | public User getUserByName(String name); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.service.impl; 2 | 3 | import cn.mccreefei.dao.LoginInfoDAO; 4 | import cn.mccreefei.dao.MessageRecordDAO; 5 | import cn.mccreefei.dao.UserDAO; 6 | import cn.mccreefei.model.LoginInfoDo; 7 | import cn.mccreefei.model.MessageRecordDo; 8 | import cn.mccreefei.model.User; 9 | import cn.mccreefei.service.UserService; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | /** 14 | * 用户service实现类 15 | */ 16 | @Service 17 | public class UserServiceImpl implements UserService { 18 | @Autowired 19 | private UserDAO userDAO; 20 | @Autowired 21 | private LoginInfoDAO loginInfoDAO; 22 | @Autowired 23 | private MessageRecordDAO messageRecordDAO; 24 | 25 | 26 | public User validateUserPassword(String name, String password) { 27 | return userDAO.queryUser(name, password); 28 | } 29 | 30 | public boolean isExistUser(String name) { 31 | User user = userDAO.queryUserByName(name); 32 | return user != null; 33 | } 34 | 35 | public void insertUser(String name, String password) { 36 | userDAO.insertUser(name, password); 37 | } 38 | 39 | @Override 40 | public void addUserLoginInfo(LoginInfoDo loginInfoDo) { 41 | loginInfoDAO.addLoginInfo(loginInfoDo); 42 | } 43 | 44 | @Override 45 | public void addUserMessageRecord(MessageRecordDo messageRecordDo) { 46 | messageRecordDAO.addMessageRecord(messageRecordDo); 47 | } 48 | 49 | @Override 50 | public User getUserByName(String name) { 51 | return userDAO.getUserByName(name); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/web/LoginController.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.web; 2 | 3 | import cn.mccreefei.enums.LoginTypeEnum; 4 | import cn.mccreefei.model.*; 5 | import cn.mccreefei.service.UserService; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.messaging.simp.SimpMessagingTemplate; 10 | import org.springframework.messaging.simp.annotation.SubscribeMapping; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpSession; 16 | import javax.sql.DataSource; 17 | import java.util.Date; 18 | 19 | /** 20 | *登录和注册的控制器 21 | */ 22 | @Controller 23 | public class LoginController { 24 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 25 | @Autowired 26 | private UserService userService; //用户service类 27 | @Autowired 28 | private SimpMessagingTemplate messagingTemplate; //消息模板 29 | @Autowired 30 | private ParticipantRepository participantRepository; //在线用户存储 31 | 32 | private static final String SUBSCRIBE_LOGIN_URI = "/topic/login"; //订阅的登录地址 33 | 34 | /** 35 | * 反馈前端ajax登录的消息 36 | * @param user 37 | * @return 38 | */ 39 | @RequestMapping(value = "/reply/login", method = RequestMethod.POST) 40 | @ResponseBody 41 | public ReplyLoginMessage replayLoginMessage(@RequestBody User user){ 42 | if (user.getName() == null || user.getName().trim().equals("") 43 | || user.getPassword() == null || user.getPassword().equals("")){ 44 | return new ReplyLoginMessage(false, ReplyLoginMessage.USER_NAME_OR_PASSWORD_NULL); 45 | } 46 | boolean isExist = userService.isExistUser(user.getName()); 47 | if (!isExist){ 48 | return new ReplyLoginMessage(false, ReplyLoginMessage.USER_NAME_NOT_EXIST); 49 | } 50 | User res = userService.validateUserPassword(user.getName(), user.getPassword()); 51 | if (res == null){ 52 | return new ReplyLoginMessage(false, ReplyLoginMessage.USER_PASSWORD_WRONG); 53 | } 54 | return new ReplyLoginMessage(true); 55 | } 56 | 57 | /** 58 | * 反馈前端ajax注册的消息 59 | * @param user 60 | * @return 61 | */ 62 | @RequestMapping(value = "/reply/regist", method = RequestMethod.POST) 63 | @ResponseBody 64 | public ReplyRegistMessage replyRegistMessage(@RequestBody User user){ 65 | boolean isExist = userService.isExistUser(user.getName()); 66 | if (isExist){ 67 | return new ReplyRegistMessage(false, ReplyRegistMessage.USER_NAME_EXIST); 68 | } 69 | if (user.getPassword() != null){ 70 | userService.insertUser(user.getName(), user.getPassword()); 71 | } 72 | return new ReplyRegistMessage(true); 73 | } 74 | 75 | /** 76 | * 登录进入聊天室 77 | * @param user 78 | * @param request 79 | * @return 80 | */ 81 | @RequestMapping(value = "/chat", method = RequestMethod.POST) 82 | public String loginIntoChatRoom(User user, HttpServletRequest request){ 83 | user = userService.validateUserPassword(user.getName(), user.getPassword()); 84 | if (user == null){ 85 | return "login"; 86 | } 87 | user.setLoginDate(new Date()); 88 | user.setPassword(null); //设空防止泄露给其他用户 89 | HttpSession session = request.getSession(); 90 | session.setAttribute("user", user); 91 | //保存登陆信息 92 | LoginInfoDo loginInfo = LoginInfoDo.builder().userId(user.getId()).userName(user.getName()). 93 | status(LoginTypeEnum.LOGIN.getCode()).createTime(new Date()).build(); 94 | userService.addUserLoginInfo(loginInfo); 95 | 96 | messagingTemplate.convertAndSend(SUBSCRIBE_LOGIN_URI, user); 97 | participantRepository.add(user.getName(), user); 98 | logger.info(user.getLoginDate() + ", " + user.getName() + " login."); 99 | return "chatroom"; 100 | } 101 | 102 | /** 103 | * 登录页面 104 | * @return 105 | */ 106 | @RequestMapping(value = {"/", "/index", ""}, method = RequestMethod.GET) 107 | public String index(){ 108 | return "index"; 109 | } 110 | 111 | /** 112 | * 返回当前在线人数 113 | * @return 114 | */ 115 | @SubscribeMapping("/chat/participants") 116 | public Long getActiveUserNumber(){ 117 | return Long.valueOf(participantRepository.getActiveSessions().values().size()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/web/MessageController.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.web; 2 | 3 | import cn.mccreefei.enums.MessageTypeEnum; 4 | import cn.mccreefei.model.Message; 5 | import cn.mccreefei.model.MessageRecordDo; 6 | import cn.mccreefei.model.User; 7 | import cn.mccreefei.service.UserService; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.messaging.handler.annotation.MessageMapping; 12 | import org.springframework.messaging.simp.SimpMessagingTemplate; 13 | import org.springframework.stereotype.Controller; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RequestMethod; 16 | import org.springframework.web.bind.annotation.RequestParam; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | import org.springframework.web.multipart.MultipartFile; 19 | 20 | import javax.servlet.http.HttpServletRequest; 21 | import java.io.BufferedOutputStream; 22 | import java.io.File; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.util.Date; 26 | 27 | /** 28 | * 发送消息控制器 29 | */ 30 | @Controller 31 | public class MessageController { 32 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 33 | 34 | private static final String SUBSCRIBE_MESSAGE_URI = "/topic/chat/message"; //订阅接收消息地址 35 | 36 | private static final String IMAGE_PREFIX = "/resources/media/image/"; //服务器储存上传图片地址的前缀 37 | 38 | @Autowired 39 | private SimpMessagingTemplate messagingTemplate; 40 | @Autowired 41 | private UserService userService; 42 | 43 | /** 44 | * 接收并且转发消息 45 | * @param message 46 | */ 47 | @MessageMapping("/chat/message") 48 | public void receiveMessage(Message message){ 49 | message.setSendDate(new Date()); 50 | message.setMessageType("text"); 51 | logger.info(message.getSendDate() + "," + message.getUserName() + " send a message:" + message.getContent()); 52 | //保存聊天信息 53 | User userByName = userService.getUserByName(message.getUserName()); 54 | MessageRecordDo messageRecordDo = MessageRecordDo.messageRecordBuilder() 55 | .userId(userByName == null ? null : userByName.getId()) 56 | .userName(message.getUserName()).content(message.getContent()) 57 | .messageType(MessageTypeEnum.TEXT.getCode()).createTime(new Date()).build(); 58 | userService.addUserMessageRecord(messageRecordDo); 59 | messagingTemplate.convertAndSend(SUBSCRIBE_MESSAGE_URI, message); 60 | } 61 | 62 | /** 63 | * 接收转发图片 64 | * @param request 65 | * @param imageFile 66 | * @param userName 67 | * @return 68 | */ 69 | @RequestMapping(value = "/upload/image", method = RequestMethod.POST) 70 | @ResponseBody 71 | public String handleUploadImage(HttpServletRequest request, @RequestParam("image")MultipartFile imageFile, 72 | @RequestParam("userName")String userName){ 73 | if (!imageFile.isEmpty()){ 74 | String imageName = userName + "_" + (int)(Math.random() * 1000000) + ".jpg"; 75 | String path = request.getSession().getServletContext().getRealPath(IMAGE_PREFIX) +"/" + imageName; 76 | File localImageFile = new File(path); 77 | try { 78 | //上传图片到目录 79 | byte[] bytes = imageFile.getBytes(); 80 | BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(localImageFile)); 81 | bufferedOutputStream.write(bytes); 82 | bufferedOutputStream.close(); 83 | Message message = new Message(); 84 | message.setMessageType("image"); 85 | message.setUserName(userName); 86 | message.setSendDate(new Date()); 87 | message.setContent(request.getContextPath() + IMAGE_PREFIX + imageName); 88 | 89 | //保存发送图片信息 90 | User userByName = userService.getUserByName(message.getUserName()); 91 | MessageRecordDo messageRecordDo = MessageRecordDo.messageRecordBuilder() 92 | .userId(userByName == null ? null : userByName.getId()) 93 | .userName(userName).content(message.getContent()) 94 | .messageType(MessageTypeEnum.IMAGE.getCode()).createTime(new Date()).build(); 95 | userService.addUserMessageRecord(messageRecordDo); 96 | 97 | messagingTemplate.convertAndSend(SUBSCRIBE_MESSAGE_URI, message); 98 | } catch (IOException e) { 99 | logger.error("图片上传失败:" + e.getMessage(), e); 100 | return "upload false"; 101 | } 102 | } 103 | return "upload success"; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/web/websocket/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.web.websocket; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.messaging.simp.config.MessageBrokerRegistry; 6 | import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; 7 | import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; 8 | import org.springframework.web.socket.config.annotation.StompEndpointRegistry; 9 | import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; 10 | 11 | import javax.servlet.ServletContext; 12 | 13 | /** 14 | * Spring websocket配置类 15 | */ 16 | @Configuration 17 | @EnableWebSocketMessageBroker 18 | public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 19 | /** 20 | * 定义接收/websocket时采用wensocket连接,添加HttpSessionHandshakeInterceptor是为了websocket握手前将httpsession中的属性 21 | * 添加到websocket session中,withSockJS添加对sockJS的支持 22 | * 23 | * @param stompEndpointRegistry 24 | */ 25 | public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) { 26 | stompEndpointRegistry.addEndpoint("/websocket").addInterceptors(new HttpSessionHandshakeInterceptor()).withSockJS(); 27 | } 28 | 29 | /** 30 | * 配置消息代理,以/app为头的url将会先经过MessageMapping 31 | * /topic直接进入消息代理 32 | * 33 | * @param registry 34 | */ 35 | 36 | @Override 37 | public void configureMessageBroker(MessageBrokerRegistry registry) { 38 | registry.setApplicationDestinationPrefixes("/app"); 39 | registry.enableSimpleBroker("/topic"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/mccreefei/web/websocket/WebSocketDisconnectHandler.java: -------------------------------------------------------------------------------- 1 | package cn.mccreefei.web.websocket; 2 | 3 | import cn.mccreefei.enums.LoginTypeEnum; 4 | import cn.mccreefei.model.LoginInfoDo; 5 | import cn.mccreefei.model.ParticipantRepository; 6 | import cn.mccreefei.model.User; 7 | import cn.mccreefei.service.UserService; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.context.ApplicationListener; 12 | import org.springframework.messaging.simp.SimpMessagingTemplate; 13 | import org.springframework.messaging.simp.stomp.StompHeaderAccessor; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.socket.messaging.SessionDisconnectEvent; 16 | 17 | import java.util.Date; 18 | import java.util.Map; 19 | 20 | /** 21 | * websocket断开连接处理,监听SessionDisconnectEvent事件,当有人下线就通知其他用户 22 | */ 23 | @Component 24 | public class WebSocketDisconnectHandler implements ApplicationListener { 25 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 26 | @Autowired 27 | private SimpMessagingTemplate messagingTemplate; 28 | 29 | @Autowired 30 | private ParticipantRepository participantRepository; 31 | 32 | @Autowired 33 | private UserService userService; 34 | 35 | private final static String SUBSCRIBE_LOGOUT_URI = "/topic/logout"; 36 | 37 | /** 38 | * 当sessionDisconnectEvent发布时,此方法将被调用,从事件中的message取出websocket sessionAttributes 39 | * 从中取出离开的User,将在线用户map中删除该用户,通知其他用户 40 | * @param sessionDisconnectEvent 41 | */ 42 | public void onApplicationEvent(SessionDisconnectEvent sessionDisconnectEvent) { 43 | Map activeSessions = participantRepository.getActiveSessions(); 44 | StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionDisconnectEvent.getMessage()); 45 | Map sessionAttributes = headerAccessor.getSessionAttributes(); 46 | User disconnectSession = (User) sessionAttributes.get("user"); 47 | String disconnectUserName = disconnectSession.getName(); 48 | if (participantRepository.containsUserName(disconnectUserName)){ 49 | User removeUser = participantRepository.remove(disconnectUserName); 50 | removeUser.setLogoutDate(new Date()); 51 | //保存登出信息 52 | User userByName = userService.getUserByName(removeUser.getName()); 53 | LoginInfoDo loginInfo = LoginInfoDo.builder().userId(userByName == null ? null : userByName.getId()) 54 | .userName(removeUser.getName()). 55 | status(LoginTypeEnum.LOGOUT.getCode()).createTime(new Date()).build(); 56 | userService.addUserLoginInfo(loginInfo); 57 | logger.info(removeUser.getLogoutDate() + ", " + removeUser.getName() + " logout."); 58 | messagingTemplate.convertAndSend(SUBSCRIBE_LOGOUT_URI, removeUser); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/map/LoginInfoMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INSERT INTO login_info(user_id, user_name, status, create_time) 6 | VALUES (#{userId}, #{userName}, #{status}, #{createTime}) 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/map/MessageRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INSERT INTO message_record(user_id, user_name, message_type, content, create_time) 6 | VALUES (#{userId}, #{userName}, #{messageType}, #{content}, #{createTime}) 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/map/userMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 12 | 16 | 21 | 22 | 23 | 24 | INSERT INTO user(name, password) VALUES(#{name}, #{password}) 25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/spring/spring-dao.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/spring/spring-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/resources/system-config.properties: -------------------------------------------------------------------------------- 1 | jdbc.driver = com.mysql.jdbc.Driver 2 | jdbc.url = jdbc:mysql://127.0.0.1:3306/easychat 3 | jdbc.user = root 4 | jdbc.password = admin 5 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/chatroom.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 2 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 | 4 | 5 | EasyChat 6 | 7 | " type="image/x-icon"> 8 | 9 | 10 | "> 11 |
12 | 18 |
19 |
20 |
21 |
22 | "> 23 | "> 24 | "> 25 |
26 | 27 | 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | "> 54 | 55 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 | 4 | EasyChat登录 5 | " type="image/x-icon"> 6 | 7 | "> 8 |

欢迎访问EasyChat :)

9 | 10 | 107 |
推荐使用Chrome内核浏览器访问本站
108 | 109 | 110 | 111 | "> 112 | 113 | " rel="stylesheet" type="text/css" /> 114 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | Archetype Created Web Application 8 | 9 | 10 | dispatcherServlet 11 | org.springframework.web.servlet.DispatcherServlet 12 | 13 | contextConfigLocation 14 | classpath:spring/spring-*.xml 15 | 16 | 1 17 | 18 | 52428800 19 | 52428800 20 | 0 21 | 22 | true 23 | 24 | 25 | 26 | dispatcherServlet 27 | / 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/webapp/resources/css/login.css: -------------------------------------------------------------------------------- 1 | html { 2 | 3 | } 4 | body { 5 | font-family:"Microsoft Yahei"; 6 | font-size:12px; 7 | margin:0; 8 | } 9 | ul { 10 | padding:0; 11 | margin:0; 12 | } 13 | ul li { 14 | list-style-type:none; 15 | } 16 | a { 17 | text-decoration:none; 18 | } 19 | a:hover { 20 | text-decoration:none;color:#f00; 21 | } 22 | .cl{ clear: both;} 23 | input[type="text"]:focus, input[type="password"]:focus { 24 | outline:none; 25 | } 26 | input::-ms-clear { 27 | display:none; 28 | } 29 | .login { 30 | margin:0 auto; 31 | width:370px; 32 | border:2px solid #eee; 33 | border-bottom:none; 34 | position:relative; 35 | } 36 | .header { 37 | height:50px; 38 | border-bottom:1px solid #e2e2e2; 39 | position:relative; 40 | font-family:"Microsoft Yahei"; 41 | } 42 | .header .switch { 43 | height:45px; 44 | position:absolute; 45 | left:60px; 46 | bottom:0; 47 | font-size:16px; 48 | } 49 | .header .switch #switch_qlogin { 50 | margin-right:85px; 51 | } 52 | .header .switch .switch_btn { 53 | color:#999; 54 | display:inline-block; 55 | height:45px; 56 | line-height:45px; 57 | outline:none; 58 | *hide-focus:expression(this.hideFocus=true); 59 | } 60 | .header .switch .switch_btn_focus { 61 | color:#333; 62 | display:inline-block; 63 | height:45px; 64 | line-height:45px; 65 | outline:none; 66 | *hide-focus:expression(this.hideFocus=true); 67 | } 68 | .header .switch .switch_btn:hover { 69 | color:#333; 70 | text-decoration:none; 71 | } 72 | .header .switch .switch_btn_focus:hover { 73 | text-decoration:none; 74 | } 75 | #switch_bottom { 76 | position:absolute; 77 | bottom:-1px;_bottom:-2px; 78 | border-bottom:2px solid #848484; 79 | } 80 | 81 | .web_login { 82 | width:370px; 83 | position:relative; 84 | } 85 | #web_login{_left:60px;*left:0;} 86 | .web_login .login_form { 87 | width:272px; 88 | margin:0 auto; 89 | } 90 | .web_login .reg_form { 91 | width:300px; 92 | margin:0 auto; 93 | } 94 | .web_login .input-tips { 95 | float:left; 96 | margin-top:10px; 97 | width:50px; 98 | height:42px; 99 | font-size:16px; 100 | line-height:42px; 101 | font-family:"Hiragino Sans GB", "Microsoft Yahei"; 102 | } 103 | .web_login .input-tips2 { 104 | float:left; 105 | text-align:right; 106 | padding-right:10px; 107 | width:75px; 108 | height:30px; 109 | font-size:16px; 110 | margin-top:10px; 111 | clear:both; 112 | line-height:30px; 113 | font-family:"Hiragino Sans GB", "Microsoft Yahei"; 114 | } 115 | .web_login .inputOuter { 116 | width:200px; 117 | height:42px; 118 | margin-top:10px; 119 | float:left; 120 | 121 | } 122 | .web_login .inputOuter2 { 123 | width:200px; 124 | margin-top:6px;margin-top:5px\9; 125 | float:left; 126 | 127 | } 128 | .web_login .inputstyle { 129 | width:200px; 130 | height:38px; 131 | padding-left:5px; 132 | line-height:30px;line-height:38px; 133 | border:1px solid #D7D7D7; 134 | background:#fff; 135 | color:#333;border-radius:2px; 136 | font-family:Verdana, Tahoma, Arial; 137 | font-size:16px; 138 | ime-mode:disabled; 139 | } 140 | .web_login input.inputstyle2:focus,.web_login input.inputstyle:focus{border:1px solid #198BD4;box-shadow:0 0 2px #198BD4;} 141 | .web_login .inputstyle2 { 142 | width:200px; 143 | height:34px; 144 | padding-left:5px; 145 | line-height:34px; 146 | border:1px solid #D7D7D7; 147 | background:#fff; 148 | color:#333;border-radius:2px; 149 | font-family:Verdana, Tahoma, Arial; 150 | font-size:16px; 151 | ime-mode:disabled; 152 | } 153 | .web_login .uinArea { 154 | height:55px; 155 | position:relative; 156 | z-index:10; 157 | } 158 | .web_login .pwdArea { 159 | height:55px; 160 | margin-bottom:10px; 161 | position:relative; 162 | z-index:3; 163 | } 164 | .web_qr_login { 165 | position:relative; 166 | 167 | overflow:hidden; 168 | } 169 | 170 | .cue { 171 | height:40px; 172 | line-height:40px; 173 | font-size:14px; 174 | border:1px #CCCCCC solid; 175 | margin-top:10px;margin-bottom:5px; 176 | text-align:center; 177 | font-family:"Hiragino Sans GB", "Microsoft Yahei"; 178 | } 179 | .login { 180 | background-color:#ffffff; 181 | } 182 | 183 | h1{margin:80px auto 50px auto;text-align:center;color:#fff;margin-left:-25px;font-size:35px;font-weight: bold;text-shadow: 0px 1px 1px #555;} 184 | h1 sup{ 185 | font-size: 18px; 186 | font-style: normal; 187 | position: absolute; 188 | margin-left: 10px;} 189 | .login {border:0;padding:5px 0; 190 | background: #fff; 191 | margin: 0 auto; 192 | -webkit-box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, .3); 193 | box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, .3);} 194 | 195 | .web_login{padding-bottom:20px;} 196 | 197 | .jianyi{color:#fff;text-align:center;margin-top:25px;color:#B3B8C4;} 198 | .reg_form li { 199 | height: 55px; 200 | } 201 | .cue { 202 | margin-top: 15px; 203 | margin-bottom: 10px;border:1px solid #eee;border-radius:3px; 204 | } 205 | .web_login input.inputstyle2:focus, .web_login input.inputstyle:focus { 206 | border: 1px solid #5796f; 207 | box-shadow: 0 0 0; 208 | } 209 | .web_login .reg_form { 210 | width: 300px; 211 | margin: 0 auto; 212 | } 213 | .web_login .inputstyle2 {border-radius:2px;width:210px;} 214 | .web_login .input-tips2 { 215 | padding-right: 5px; 216 | width: 80px;_width: 75px;_font-size:12px;} 217 | .button_blue 218 | { 219 | display:inline-block; 220 | float:left; 221 | height:41px;border-radius:4px; 222 | background:#2795dc;border:none;cursor:pointer; 223 | border-bottom:3px solid #0078b3;*border-bottom:none; 224 | color:#fff; 225 | font-size:16px;padding:0 10px;*width:140px; 226 | text-align:center;outline:none;font-family: "Microsoft Yahei",Arial, Helvetica, sans-serif; 227 | } 228 | input.button_blue:hover 229 | { 230 | background:#0081c1; 231 | border-bottom:3px solid #006698;*border-bottom:none; 232 | color:#fff; 233 | text-decoration:none; 234 | } 235 | a.zcxy {text-decoration: underline;line-height:58px;margin-left:15px;color: #959ca8;} 236 | .web_login .login_form {margin-top:30px;} 237 | .web_login .uinArea { 238 | height: 60px;} 239 | .header .switch{left:70px;} 240 | 241 | -------------------------------------------------------------------------------- /src/main/webapp/resources/css/main.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | font-family: sans-serif; 4 | } 5 | 6 | 7 | .wrapper { 8 | width: 600px; 9 | height: 790px; 10 | padding: 5px; 11 | margin: 0 auto; 12 | background-color: #ddd; 13 | } 14 | 15 | #activeUserWraper { 16 | width: 100%; 17 | height: 30px; 18 | margin-top: 30px; 19 | } 20 | 21 | #activeUserWraper span { 22 | font-size: large; 23 | } 24 | 25 | .banner { 26 | height: 120px; 27 | width: 100%; 28 | } 29 | .banner span { 30 | float: left; 31 | display: inline-block; 32 | } 33 | .controls { 34 | height: 150px; 35 | margin: 5px 0px; 36 | position: relative; 37 | } 38 | 39 | 40 | #historyMsg { 41 | height: 400px; 42 | background-color: #fff; 43 | overflow: auto; 44 | padding: 2px; 45 | } 46 | #historyMsg p { 47 | font-size: 20px; 48 | } 49 | #historyMsg img { 50 | max-width: 90%; 51 | 52 | } 53 | .timespan { 54 | color: #ddd; 55 | font-size: 16px; 56 | } 57 | .items { 58 | height: 30px; 59 | margin-bottom: 8px; 60 | } 61 | /*custom the file input*/ 62 | 63 | .imageLable { 64 | position: relative; 65 | } 66 | #sendImage { 67 | position: absolute; 68 | width: 1px; 69 | height: 1px; 70 | left: 0; 71 | opacity: 0; 72 | overflow: hidden; 73 | } 74 | /*end custom file input*/ 75 | 76 | #messageInput { 77 | height: 170px; 78 | max-height: 170px; 79 | } 80 | 81 | #emojiWrapper { 82 | display: none; 83 | width: 500px; 84 | bottom: 105px; 85 | position: absolute; 86 | background-color: #aaa; 87 | box-shadow: 0 0 10px #555; 88 | } 89 | #emojiWrapper img { 90 | margin: 2px; 91 | padding: 2px; 92 | width: 25px; 93 | height: 25px; 94 | } 95 | #emojiWrapper img:hover { 96 | background-color: blue; 97 | } 98 | 99 | .emoji{ 100 | display: inline; 101 | } 102 | footer { 103 | text-align: center; 104 | } -------------------------------------------------------------------------------- /src/main/webapp/resources/image/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/image/1.jpg -------------------------------------------------------------------------------- /src/main/webapp/resources/image/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/image/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/resources/js/chatroom.js: -------------------------------------------------------------------------------- 1 | var stompClient = null; 2 | $(function () { 3 | connect(); 4 | /** 5 | * 键盘enter事件,用来发送消息 6 | */ 7 | $("#messageInput").bind("keyup", function (event) { 8 | if (event.keyCode == 13){ 9 | sendMessage(); 10 | } 11 | }); 12 | 13 | /** 14 | * 清除聊天窗口的所有内容 15 | */ 16 | $("#clearBtn").click(function () { 17 | $("#historyMsg").empty(); 18 | $("#messageInput").focus(); 19 | }); 20 | 21 | /** 22 | * 上传图片发送 23 | */ 24 | $("#sendImage").bind("change", function () { 25 | if (this.files.length != 0){ 26 | $.ajax({ 27 | url: $("#uploadUrl").val(), 28 | type: 'POST', 29 | cache: false, 30 | data: new FormData($('#sendImageForm')[0]), 31 | processData: false, 32 | contentType: false 33 | }).done(function(res) { 34 | console.log(res); 35 | }).fail(function(res) { 36 | console.log(res); 37 | }); 38 | } 39 | }); 40 | initEmoji(); 41 | $("#sendImageBtn").click(function () { 42 | $("#sendImage").trigger("click"); 43 | }) 44 | 45 | }); 46 | /** 47 | * 预加载emoji图片 48 | */ 49 | function initEmoji() { 50 | var emojiContainer = $("#emojiWrapper"); 51 | var documentFragment = document.createDocumentFragment(); 52 | for (var i = 69; i > 0; i--){ 53 | var emojiItem = document.createElement("img"); 54 | emojiItem.src = $("#emojiBaseUri").val().trim() + i + ".gif"; 55 | emojiItem.title = i; 56 | documentFragment.appendChild(emojiItem); 57 | } 58 | emojiContainer.append(documentFragment); 59 | 60 | $("#emoji").click(function (event) { 61 | emojiContainer.css("display", "block"); 62 | event.stopPropagation(); //阻止事件的传递,防止body监听到 63 | }); 64 | 65 | $("body").click(function (event) { 66 | if (event.target != emojiContainer){ 67 | emojiContainer.css("display", "none"); 68 | } 69 | }); 70 | 71 | $("#emojiWrapper").click(function (event) { 72 | var target = event.target; 73 | if (target.nodeName.toLowerCase() == "img"){ 74 | var messageInput = $("#messageInput"); 75 | messageInput.val(messageInput.val() + "[EMOJI:" + target.title + "]"); 76 | messageInput.focus(); 77 | } 78 | }) 79 | 80 | } 81 | /** 82 | * 客户端连接服务端websocket 83 | * 并且订阅一系列频道,用来接收不同种类的消息 84 | * /app/chat/participants :当前在线人数的消息,只会接收一次 85 | * /topic/login : 新登录用户的消息 86 | * /topic/chat/message : 聊天内容消息 87 | * /topic/logout : 用户离线的消息 88 | * 服务器发回json实例{"userName":"chris","sendDate":1494664021793,"content":"hello","messageType":"text"} 89 | * messageType分为:text与image 90 | */ 91 | function connect() { 92 | var socket = new SockJS($("#websocketUrl").val().trim()); 93 | stompClient = Stomp.over(socket); 94 | stompClient.connect({}, function(frame){ 95 | stompClient.subscribe("/app/chat/participants", function (message) { 96 | showActiveUserNumber(message.body); 97 | var user = "系统消息"; 98 | var date = null; 99 | var msg = $("#myName").val() + "加入聊天!"; 100 | showNewMessage(user, date, msg); 101 | }); 102 | stompClient.subscribe("/topic/login", function (message) { 103 | showNewUser(message.body); 104 | }); 105 | stompClient.subscribe("/topic/chat/message", function (message) { 106 | var json = JSON.parse(message.body); 107 | var messageType = json.messageType; 108 | var user = json.userName; 109 | var date = json.sendDate; 110 | var msg = json.content; 111 | if (messageType == "text"){ 112 | showNewMessage(user, date, msg); 113 | }else if (messageType == "image"){ 114 | showNewImage(user, date, msg); 115 | } 116 | 117 | }) 118 | stompClient.subscribe("/topic/logout", function (message) { 119 | showUserLogout(message.body); 120 | }) 121 | 122 | }); 123 | } 124 | /** 125 | * 显示用户离线消息 126 | * @param message 127 | */ 128 | function showUserLogout(message) { 129 | var json = JSON.parse(message); 130 | var logoutUser = json.name; 131 | var date = json.logoutDate; 132 | var user = "系统消息"; 133 | var msg = logoutUser + "离开了聊天室~"; 134 | showNewMessage(user, date, msg); 135 | showSubActiveUserNumber(); 136 | } 137 | /** 138 | * 显示新用户登录的消息 139 | * @param message 140 | */ 141 | function showNewUser(message) { 142 | var json = JSON.parse(message); 143 | var newUser = json.name; 144 | var date = json.loginDate; 145 | var user = '系统消息'; 146 | var msg = newUser + "加入聊天!"; 147 | showNewMessage(user, date, msg); 148 | showAddActiveUserNumber(); 149 | 150 | } 151 | /** 152 | * 显示当前在线人数 153 | * @param number 154 | */ 155 | function showActiveUserNumber(number) { 156 | $("#status").text(number); 157 | } 158 | /** 159 | * 在线人数加1 160 | */ 161 | function showAddActiveUserNumber() { 162 | var number = parseInt($("#status").text()); 163 | number = number + 1; 164 | $("#status").text(number); 165 | } 166 | /** 167 | * 在线人数减1 168 | */ 169 | function showSubActiveUserNumber() { 170 | var number = parseInt($("#status").text()); 171 | number = number - 1; 172 | $("#status").text(number); 173 | } 174 | /** 175 | * 格式化时间,参数为null显示当前客户端时间 176 | * @param dateTime 177 | * @returns {string} 178 | */ 179 | function formatDate(dateTime) { 180 | var date = dateTime == null ? new Date() : new Date(dateTime); 181 | var year = date.getFullYear(); 182 | var month = date.getMonth() + 1; 183 | var day = date.getDate(); 184 | var hour = date.getHours(); 185 | hour = hour < 10 ? '0'+""+hour : hour; 186 | var minute = date.getMinutes(); 187 | minute = minute < 10 ? '0'+""+minute : minute; 188 | var second = date.getSeconds(); 189 | second = second < 10 ? '0'+""+second : second; 190 | return year + "-" + month + "-" + day +" " + hour + ":" + minute + ":" + second; 191 | } 192 | 193 | /** 194 | * 显示新消息 195 | * @param user 发消息的用户或者‘系统消息’ 196 | * @param date 发消息的时间(未格式化) 197 | * @param msg 消息内容 198 | */ 199 | function showNewMessage(user, date, msg) { 200 | var container = document.getElementById("historyMsg"); 201 | var msgToDisplay = document.createElement('p'); 202 | if (user == "系统消息"){ 203 | msgToDisplay.style.color = 'red'; 204 | } 205 | var dateTime = formatDate(date); 206 | msg = showEmoji(msg); 207 | msgToDisplay.innerHTML = '' + dateTime + '
[' + user + "] : " + msg; 208 | container.append(msgToDisplay); 209 | container.scrollTop = container.scrollHeight; 210 | } 211 | /** 212 | * 正则表达式显示消息中的emoji图片 213 | * @param message 214 | * @returns {*} 返回添加emoji图片标签后的消息 215 | */ 216 | function showEmoji(message) { 217 | var result = message, 218 | regrex = /\[EMOJI:\d+\]/g, 219 | match; 220 | while (match = regrex.exec(message)){ 221 | var emojiIndex = match[0].slice(7, -1); 222 | var emojiUrl = $("#emojiBaseUri").val().trim() + emojiIndex + ".gif"; 223 | result = result.replace(match[0], ''); 224 | } 225 | return result; 226 | } 227 | 228 | /** 229 | * 显示用户发送的图片 230 | * @param user 用户名称 231 | * @param date 用户发送的时间(未格式化) 232 | * @param url 图片url 233 | */ 234 | function showNewImage(user, date, url) { 235 | var container = document.getElementById("historyMsg"); 236 | var msgToDisplay = document.createElement('p'); 237 | var dateTime = formatDate(date); 238 | msgToDisplay.innerHTML = '' + dateTime + '
[' + user + '] :
' + 239 | ''; 240 | container.append(msgToDisplay); 241 | container.scrollTop = container.scrollHeight; 242 | } 243 | /** 244 | * 发送输入框中的信息 245 | */ 246 | function sendMessage() { 247 | var content = $("#messageInput").val(); 248 | if (content.trim().length != 0){ 249 | $("#messageInput").val(''); 250 | stompClient.send("/app/chat/message", {}, JSON.stringify({ 251 | 'userName' : $("#myName").val(), 252 | 'content' : content 253 | })); 254 | } 255 | } 256 | 257 | -------------------------------------------------------------------------------- /src/main/webapp/resources/js/login.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | /** 3 | * 登录按钮点击事件 4 | */ 5 | $("#loginBtn").click(function () { 6 | console.log("into click loginBtn"); 7 | var replyUrl = $("#replayLoginUrl").val().trim(); 8 | var username = $("#u").val().trim(); 9 | var password = $("#p").val().trim(); 10 | if (username.length == 0 || password.length == 0) { 11 | sweetAlert("哎呦…出错了…", "用户名或密码为空,请填写!", "error"); 12 | return; 13 | } 14 | /** 15 | * 返回data类型 16 | * {successed : true | false} 登录是否成功 17 | * {errStatus : 1 | 2 | 3} 当successed为false会有errStatus错误状态信息 18 | * 其中 1:该用户名还没有注册 19 | * 2:密码错误 20 | * 3:用户名或者密码为空(防止第三方插件登录) 21 | */ 22 | $.ajax({ 23 | type: "POST", 24 | url: replyUrl, 25 | data: JSON.stringify({'name': username, 'password': password}), 26 | dataType: "json", 27 | contentType: "application/json", 28 | success: function (data) { 29 | console.log(data); 30 | var successed = data.successed; 31 | if (successed) { 32 | $("#login_form").submit(); 33 | } else { 34 | var errStatus = data.errStatus; 35 | if (errStatus == 1) { 36 | sweetAlert("哎呦…出错了…", "该用户名尚未注册,请前往注册~", "error"); 37 | return; 38 | } else if (errStatus == 2) { 39 | sweetAlert("哎呦…出错了…", "密码错误!请重新填写~", "error"); 40 | $("#p").focus(); 41 | } else if (errStatus == 3) { 42 | sweetAlert("哎呦…出错了…", "用户名或密码未填写~", "error"); 43 | returne 44 | } else { 45 | sweetAlert("哎呦…出错了…", "服务器出现未知错误~", "error"); 46 | return; 47 | } 48 | } 49 | } 50 | }); 51 | }); 52 | 53 | 54 | /** 55 | * 用户名输入框失去焦点事件,ajax判断是否该名称已经被注册 56 | */ 57 | $("#user").blur(function () { 58 | var userName = $("#user").val().trim(); 59 | var sendData = JSON.stringify({'name': userName}); 60 | if (userName.length != 0) { 61 | /** 62 | * 返回data类型 63 | * {successed : true | false} 注册是否成功 64 | * {errStatus : 1 } 用户名已经被注册 65 | 66 | */ 67 | $.ajax({ 68 | type: "POST", 69 | url: $("#replyRegistUrl").val().trim(), 70 | data: sendData, 71 | dataType: "json", 72 | contentType: "application/json", 73 | success: function (data) { 74 | console.log(data); 75 | if (data.successed) { 76 | $('#user').css({ 77 | border: "1px solid #D7D7D7", 78 | boxShadow: "none" 79 | }); 80 | $("#userCue").html("欢迎注册EastChat!"); 81 | }else if(data.errStatus == 1){ 82 | $('#user').focus().css({ 83 | border: "1px solid red", 84 | boxShadow: "0 0 2px red" 85 | }); 86 | $('#userCue').html("该用户名已经被注册!"); 87 | } 88 | } 89 | }) 90 | } 91 | $('#user').css({ 92 | border: "1px solid #D7D7D7", 93 | boxShadow: "none" 94 | }); 95 | $("#userCue").html("欢迎注册EastChat!"); 96 | }); 97 | 98 | /** 99 | * 注册按钮点击事件 100 | */ 101 | $("#reg").click(function () { 102 | var userName = $("#user").val().trim(); 103 | var pwd1 = $("#passwd").val().trim(); 104 | var pwd2 = $("#passwd2").val().trim(); 105 | if (userName.length == 0 || pwd1.length == 0 || pwd2.length == 0){ 106 | sweetAlert("哎呦…出错了…", "您还有些内容未填写~", "error"); 107 | return; 108 | }else if (pwd1 != pwd2){ 109 | sweetAlert("哎呦…出错了…", "两次密码输入不一致,请重新填写~", "error"); 110 | }else { 111 | var sendData = JSON.stringify({'name' : userName, 'password' : pwd1}); 112 | $.ajax({ 113 | type: "POST", 114 | url: $("#replyRegistUrl").val().trim(), 115 | data: sendData, 116 | dataType: "json", 117 | contentType: "application/json", 118 | success : function (data) { 119 | if (data.successed){ 120 | sweetAlert("注册成功啦!", "快去登录~加入聊天吧~", "success"); 121 | }else { 122 | sweetAlert("哎呦…出错了…", "注册失败,请再次尝试~", "error"); 123 | } 124 | } 125 | }); 126 | } 127 | 128 | }); 129 | $('#switch_qlogin').click(function () { 130 | $('#switch_login').removeClass("switch_btn_focus").addClass('switch_btn'); 131 | $('#switch_qlogin').removeClass("switch_btn").addClass('switch_btn_focus'); 132 | $('#switch_bottom').animate({left: '0px', width: '70px'}); 133 | $('#qlogin').css('display', 'none'); 134 | $('#web_qr_login').css('display', 'block'); 135 | 136 | }); 137 | $('#switch_login').click(function () { 138 | 139 | $('#switch_login').removeClass("switch_btn").addClass('switch_btn_focus'); 140 | $('#switch_qlogin').removeClass("switch_btn_focus").addClass('switch_btn'); 141 | $('#switch_bottom').animate({left: '154px', width: '70px'}); 142 | 143 | $('#qlogin').css('display', 'block'); 144 | $('#web_qr_login').css('display', 'none'); 145 | }); 146 | if (getParam("a") == '0') { 147 | $('#switch_login').trigger('click'); 148 | } 149 | 150 | }); 151 | 152 | function logintab() { 153 | scrollTo(0); 154 | $('#switch_qlogin').removeClass("switch_btn_focus").addClass('switch_btn'); 155 | $('#switch_login').removeClass("switch_btn").addClass('switch_btn_focus'); 156 | $('#switch_bottom').animate({left: '154px', width: '96px'}); 157 | $('#qlogin').css('display', 'none'); 158 | $('#web_qr_login').css('display', 'block'); 159 | 160 | } 161 | 162 | 163 | //根据参数名获得该参数 pname等于想要的参数名 164 | function getParam(pname) { 165 | var params = location.search.substr(1); // 获取参数 平且去掉? 166 | var ArrParam = params.split('&'); 167 | if (ArrParam.length == 1) { 168 | //只有一个参数的情况 169 | return params.split('=')[1]; 170 | } 171 | else { 172 | //多个参数参数的情况 173 | for (var i = 0; i < ArrParam.length; i++) { 174 | if (ArrParam[i].split('=')[0] == pname) { 175 | return ArrParam[i].split('=')[1]; 176 | } 177 | } 178 | } 179 | } 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/1.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/10.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/11.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/12.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/13.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/14.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/15.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/16.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/17.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/18.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/19.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/2.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/20.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/21.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/22.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/23.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/24.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/25.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/26.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/27.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/28.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/29.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/3.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/30.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/31.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/32.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/33.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/34.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/35.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/36.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/37.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/38.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/39.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/4.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/40.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/41.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/42.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/43.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/44.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/45.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/46.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/47.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/48.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/49.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/5.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/50.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/51.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/52.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/53.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/54.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/55.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/56.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/57.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/58.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/59.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/6.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/60.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/61.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/62.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/63.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/64.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/65.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/66.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/67.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/68.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/69.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/7.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/8.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/emoji/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/emoji/9.gif -------------------------------------------------------------------------------- /src/main/webapp/resources/media/image/chris_619283.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MccreeFei/EasyChat/f3ba251d9f8966b8a78c10d9f5d8c1cecd914f7e/src/main/webapp/resources/media/image/chris_619283.jpg -------------------------------------------------------------------------------- /src/main/webapp/resources/plugin/sweetalert/sweetalert.css: -------------------------------------------------------------------------------- 1 | body.stop-scrolling { 2 | height: 100%; 3 | overflow: hidden; } 4 | 5 | .sweet-overlay { 6 | background-color: black; 7 | /* IE8 */ 8 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; 9 | /* IE8 */ 10 | background-color: rgba(0, 0, 0, 0.4); 11 | position: fixed; 12 | left: 0; 13 | right: 0; 14 | top: 0; 15 | bottom: 0; 16 | display: none; 17 | z-index: 10000; } 18 | 19 | .sweet-alert { 20 | background-color: white; 21 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 22 | width: 478px; 23 | padding: 17px; 24 | border-radius: 5px; 25 | text-align: center; 26 | position: fixed; 27 | left: 50%; 28 | top: 50%; 29 | margin-left: -256px; 30 | margin-top: -200px; 31 | overflow: hidden; 32 | display: none; 33 | z-index: 99999; } 34 | @media all and (max-width: 540px) { 35 | .sweet-alert { 36 | width: auto; 37 | margin-left: 0; 38 | margin-right: 0; 39 | left: 15px; 40 | right: 15px; } } 41 | .sweet-alert h2 { 42 | color: #575757; 43 | font-size: 30px; 44 | text-align: center; 45 | font-weight: 600; 46 | text-transform: none; 47 | position: relative; 48 | margin: 25px 0; 49 | padding: 0; 50 | line-height: 40px; 51 | display: block; } 52 | .sweet-alert p { 53 | color: #797979; 54 | font-size: 16px; 55 | text-align: center; 56 | font-weight: 300; 57 | position: relative; 58 | text-align: inherit; 59 | float: none; 60 | margin: 0; 61 | padding: 0; 62 | line-height: normal; } 63 | .sweet-alert fieldset { 64 | border: none; 65 | position: relative; } 66 | .sweet-alert .sa-error-container { 67 | background-color: #f1f1f1; 68 | margin-left: -17px; 69 | margin-right: -17px; 70 | overflow: hidden; 71 | padding: 0 10px; 72 | max-height: 0; 73 | webkit-transition: padding 0.15s, max-height 0.15s; 74 | transition: padding 0.15s, max-height 0.15s; } 75 | .sweet-alert .sa-error-container.show { 76 | padding: 10px 0; 77 | max-height: 100px; 78 | webkit-transition: padding 0.2s, max-height 0.2s; 79 | transition: padding 0.25s, max-height 0.25s; } 80 | .sweet-alert .sa-error-container .icon { 81 | display: inline-block; 82 | width: 24px; 83 | height: 24px; 84 | border-radius: 50%; 85 | background-color: #ea7d7d; 86 | color: white; 87 | line-height: 24px; 88 | text-align: center; 89 | margin-right: 3px; } 90 | .sweet-alert .sa-error-container p { 91 | display: inline-block; } 92 | .sweet-alert .sa-input-error { 93 | position: absolute; 94 | top: 29px; 95 | right: 26px; 96 | width: 20px; 97 | height: 20px; 98 | opacity: 0; 99 | -webkit-transform: scale(0.5); 100 | transform: scale(0.5); 101 | -webkit-transform-origin: 50% 50%; 102 | transform-origin: 50% 50%; 103 | -webkit-transition: all 0.1s; 104 | transition: all 0.1s; } 105 | .sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after { 106 | content: ""; 107 | width: 20px; 108 | height: 6px; 109 | background-color: #f06e57; 110 | border-radius: 3px; 111 | position: absolute; 112 | top: 50%; 113 | margin-top: -4px; 114 | left: 50%; 115 | margin-left: -9px; } 116 | .sweet-alert .sa-input-error::before { 117 | -webkit-transform: rotate(-45deg); 118 | transform: rotate(-45deg); } 119 | .sweet-alert .sa-input-error::after { 120 | -webkit-transform: rotate(45deg); 121 | transform: rotate(45deg); } 122 | .sweet-alert .sa-input-error.show { 123 | opacity: 1; 124 | -webkit-transform: scale(1); 125 | transform: scale(1); } 126 | .sweet-alert input { 127 | width: 100%; 128 | box-sizing: border-box; 129 | border-radius: 3px; 130 | border: 1px solid #d7d7d7; 131 | height: 43px; 132 | margin-top: 10px; 133 | margin-bottom: 17px; 134 | font-size: 18px; 135 | box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06); 136 | padding: 0 12px; 137 | display: none; 138 | -webkit-transition: all 0.3s; 139 | transition: all 0.3s; } 140 | .sweet-alert input:focus { 141 | outline: none; 142 | box-shadow: 0px 0px 3px #c4e6f5; 143 | border: 1px solid #b4dbed; } 144 | .sweet-alert input:focus::-moz-placeholder { 145 | transition: opacity 0.3s 0.03s ease; 146 | opacity: 0.5; } 147 | .sweet-alert input:focus:-ms-input-placeholder { 148 | transition: opacity 0.3s 0.03s ease; 149 | opacity: 0.5; } 150 | .sweet-alert input:focus::-webkit-input-placeholder { 151 | transition: opacity 0.3s 0.03s ease; 152 | opacity: 0.5; } 153 | .sweet-alert input::-moz-placeholder { 154 | color: #bdbdbd; } 155 | .sweet-alert input::-ms-clear { 156 | display: none; } 157 | .sweet-alert input:-ms-input-placeholder { 158 | color: #bdbdbd; } 159 | .sweet-alert input::-webkit-input-placeholder { 160 | color: #bdbdbd; } 161 | .sweet-alert.show-input input { 162 | display: block; } 163 | .sweet-alert .sa-confirm-button-container { 164 | display: inline-block; 165 | position: relative; } 166 | .sweet-alert .la-ball-fall { 167 | position: absolute; 168 | left: 50%; 169 | top: 50%; 170 | margin-left: -27px; 171 | margin-top: 4px; 172 | opacity: 0; 173 | visibility: hidden; } 174 | .sweet-alert button { 175 | background-color: #8CD4F5; 176 | color: white; 177 | border: none; 178 | box-shadow: none; 179 | font-size: 17px; 180 | font-weight: 500; 181 | -webkit-border-radius: 4px; 182 | border-radius: 5px; 183 | padding: 10px 32px; 184 | margin: 26px 5px 0 5px; 185 | cursor: pointer; } 186 | .sweet-alert button:focus { 187 | outline: none; 188 | box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); } 189 | .sweet-alert button:hover { 190 | background-color: #7ecff4; } 191 | .sweet-alert button:active { 192 | background-color: #5dc2f1; } 193 | .sweet-alert button.cancel { 194 | background-color: #C1C1C1; } 195 | .sweet-alert button.cancel:hover { 196 | background-color: #b9b9b9; } 197 | .sweet-alert button.cancel:active { 198 | background-color: #a8a8a8; } 199 | .sweet-alert button.cancel:focus { 200 | box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; } 201 | .sweet-alert button[disabled] { 202 | opacity: .6; 203 | cursor: default; } 204 | .sweet-alert button.confirm[disabled] { 205 | color: transparent; } 206 | .sweet-alert button.confirm[disabled] ~ .la-ball-fall { 207 | opacity: 1; 208 | visibility: visible; 209 | transition-delay: 0s; } 210 | .sweet-alert button::-moz-focus-inner { 211 | border: 0; } 212 | .sweet-alert[data-has-cancel-button=false] button { 213 | box-shadow: none !important; } 214 | .sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] { 215 | padding-bottom: 40px; } 216 | .sweet-alert .sa-icon { 217 | width: 80px; 218 | height: 80px; 219 | border: 4px solid gray; 220 | -webkit-border-radius: 40px; 221 | border-radius: 40px; 222 | border-radius: 50%; 223 | margin: 20px auto; 224 | padding: 0; 225 | position: relative; 226 | box-sizing: content-box; } 227 | .sweet-alert .sa-icon.sa-error { 228 | border-color: #F27474; } 229 | .sweet-alert .sa-icon.sa-error .sa-x-mark { 230 | position: relative; 231 | display: block; } 232 | .sweet-alert .sa-icon.sa-error .sa-line { 233 | position: absolute; 234 | height: 5px; 235 | width: 47px; 236 | background-color: #F27474; 237 | display: block; 238 | top: 37px; 239 | border-radius: 2px; } 240 | .sweet-alert .sa-icon.sa-error .sa-line.sa-left { 241 | -webkit-transform: rotate(45deg); 242 | transform: rotate(45deg); 243 | left: 17px; } 244 | .sweet-alert .sa-icon.sa-error .sa-line.sa-right { 245 | -webkit-transform: rotate(-45deg); 246 | transform: rotate(-45deg); 247 | right: 16px; } 248 | .sweet-alert .sa-icon.sa-warning { 249 | border-color: #F8BB86; } 250 | .sweet-alert .sa-icon.sa-warning .sa-body { 251 | position: absolute; 252 | width: 5px; 253 | height: 47px; 254 | left: 50%; 255 | top: 10px; 256 | -webkit-border-radius: 2px; 257 | border-radius: 2px; 258 | margin-left: -2px; 259 | background-color: #F8BB86; } 260 | .sweet-alert .sa-icon.sa-warning .sa-dot { 261 | position: absolute; 262 | width: 7px; 263 | height: 7px; 264 | -webkit-border-radius: 50%; 265 | border-radius: 50%; 266 | margin-left: -3px; 267 | left: 50%; 268 | bottom: 10px; 269 | background-color: #F8BB86; } 270 | .sweet-alert .sa-icon.sa-info { 271 | border-color: #C9DAE1; } 272 | .sweet-alert .sa-icon.sa-info::before { 273 | content: ""; 274 | position: absolute; 275 | width: 5px; 276 | height: 29px; 277 | left: 50%; 278 | bottom: 17px; 279 | border-radius: 2px; 280 | margin-left: -2px; 281 | background-color: #C9DAE1; } 282 | .sweet-alert .sa-icon.sa-info::after { 283 | content: ""; 284 | position: absolute; 285 | width: 7px; 286 | height: 7px; 287 | border-radius: 50%; 288 | margin-left: -3px; 289 | top: 19px; 290 | background-color: #C9DAE1; 291 | left: 50%; } 292 | .sweet-alert .sa-icon.sa-success { 293 | border-color: #A5DC86; } 294 | .sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after { 295 | content: ''; 296 | -webkit-border-radius: 40px; 297 | border-radius: 40px; 298 | border-radius: 50%; 299 | position: absolute; 300 | width: 60px; 301 | height: 120px; 302 | background: white; 303 | -webkit-transform: rotate(45deg); 304 | transform: rotate(45deg); } 305 | .sweet-alert .sa-icon.sa-success::before { 306 | -webkit-border-radius: 120px 0 0 120px; 307 | border-radius: 120px 0 0 120px; 308 | top: -7px; 309 | left: -33px; 310 | -webkit-transform: rotate(-45deg); 311 | transform: rotate(-45deg); 312 | -webkit-transform-origin: 60px 60px; 313 | transform-origin: 60px 60px; } 314 | .sweet-alert .sa-icon.sa-success::after { 315 | -webkit-border-radius: 0 120px 120px 0; 316 | border-radius: 0 120px 120px 0; 317 | top: -11px; 318 | left: 30px; 319 | -webkit-transform: rotate(-45deg); 320 | transform: rotate(-45deg); 321 | -webkit-transform-origin: 0px 60px; 322 | transform-origin: 0px 60px; } 323 | .sweet-alert .sa-icon.sa-success .sa-placeholder { 324 | width: 80px; 325 | height: 80px; 326 | border: 4px solid rgba(165, 220, 134, 0.2); 327 | -webkit-border-radius: 40px; 328 | border-radius: 40px; 329 | border-radius: 50%; 330 | box-sizing: content-box; 331 | position: absolute; 332 | left: -4px; 333 | top: -4px; 334 | z-index: 2; } 335 | .sweet-alert .sa-icon.sa-success .sa-fix { 336 | width: 5px; 337 | height: 90px; 338 | background-color: white; 339 | position: absolute; 340 | left: 28px; 341 | top: 8px; 342 | z-index: 1; 343 | -webkit-transform: rotate(-45deg); 344 | transform: rotate(-45deg); } 345 | .sweet-alert .sa-icon.sa-success .sa-line { 346 | height: 5px; 347 | background-color: #A5DC86; 348 | display: block; 349 | border-radius: 2px; 350 | position: absolute; 351 | z-index: 2; } 352 | .sweet-alert .sa-icon.sa-success .sa-line.sa-tip { 353 | width: 25px; 354 | left: 14px; 355 | top: 46px; 356 | -webkit-transform: rotate(45deg); 357 | transform: rotate(45deg); } 358 | .sweet-alert .sa-icon.sa-success .sa-line.sa-long { 359 | width: 47px; 360 | right: 8px; 361 | top: 38px; 362 | -webkit-transform: rotate(-45deg); 363 | transform: rotate(-45deg); } 364 | .sweet-alert .sa-icon.sa-custom { 365 | background-size: contain; 366 | border-radius: 0; 367 | border: none; 368 | background-position: center center; 369 | background-repeat: no-repeat; } 370 | 371 | /* 372 | * Animations 373 | */ 374 | @-webkit-keyframes showSweetAlert { 375 | 0% { 376 | transform: scale(0.7); 377 | -webkit-transform: scale(0.7); } 378 | 45% { 379 | transform: scale(1.05); 380 | -webkit-transform: scale(1.05); } 381 | 80% { 382 | transform: scale(0.95); 383 | -webkit-transform: scale(0.95); } 384 | 100% { 385 | transform: scale(1); 386 | -webkit-transform: scale(1); } } 387 | 388 | @keyframes showSweetAlert { 389 | 0% { 390 | transform: scale(0.7); 391 | -webkit-transform: scale(0.7); } 392 | 45% { 393 | transform: scale(1.05); 394 | -webkit-transform: scale(1.05); } 395 | 80% { 396 | transform: scale(0.95); 397 | -webkit-transform: scale(0.95); } 398 | 100% { 399 | transform: scale(1); 400 | -webkit-transform: scale(1); } } 401 | 402 | @-webkit-keyframes hideSweetAlert { 403 | 0% { 404 | transform: scale(1); 405 | -webkit-transform: scale(1); } 406 | 100% { 407 | transform: scale(0.5); 408 | -webkit-transform: scale(0.5); } } 409 | 410 | @keyframes hideSweetAlert { 411 | 0% { 412 | transform: scale(1); 413 | -webkit-transform: scale(1); } 414 | 100% { 415 | transform: scale(0.5); 416 | -webkit-transform: scale(0.5); } } 417 | 418 | @-webkit-keyframes slideFromTop { 419 | 0% { 420 | top: 0%; } 421 | 100% { 422 | top: 50%; } } 423 | 424 | @keyframes slideFromTop { 425 | 0% { 426 | top: 0%; } 427 | 100% { 428 | top: 50%; } } 429 | 430 | @-webkit-keyframes slideToTop { 431 | 0% { 432 | top: 50%; } 433 | 100% { 434 | top: 0%; } } 435 | 436 | @keyframes slideToTop { 437 | 0% { 438 | top: 50%; } 439 | 100% { 440 | top: 0%; } } 441 | 442 | @-webkit-keyframes slideFromBottom { 443 | 0% { 444 | top: 70%; } 445 | 100% { 446 | top: 50%; } } 447 | 448 | @keyframes slideFromBottom { 449 | 0% { 450 | top: 70%; } 451 | 100% { 452 | top: 50%; } } 453 | 454 | @-webkit-keyframes slideToBottom { 455 | 0% { 456 | top: 50%; } 457 | 100% { 458 | top: 70%; } } 459 | 460 | @keyframes slideToBottom { 461 | 0% { 462 | top: 50%; } 463 | 100% { 464 | top: 70%; } } 465 | 466 | .showSweetAlert[data-animation=pop] { 467 | -webkit-animation: showSweetAlert 0.3s; 468 | animation: showSweetAlert 0.3s; } 469 | 470 | .showSweetAlert[data-animation=none] { 471 | -webkit-animation: none; 472 | animation: none; } 473 | 474 | .showSweetAlert[data-animation=slide-from-top] { 475 | -webkit-animation: slideFromTop 0.3s; 476 | animation: slideFromTop 0.3s; } 477 | 478 | .showSweetAlert[data-animation=slide-from-bottom] { 479 | -webkit-animation: slideFromBottom 0.3s; 480 | animation: slideFromBottom 0.3s; } 481 | 482 | .hideSweetAlert[data-animation=pop] { 483 | -webkit-animation: hideSweetAlert 0.2s; 484 | animation: hideSweetAlert 0.2s; } 485 | 486 | .hideSweetAlert[data-animation=none] { 487 | -webkit-animation: none; 488 | animation: none; } 489 | 490 | .hideSweetAlert[data-animation=slide-from-top] { 491 | -webkit-animation: slideToTop 0.4s; 492 | animation: slideToTop 0.4s; } 493 | 494 | .hideSweetAlert[data-animation=slide-from-bottom] { 495 | -webkit-animation: slideToBottom 0.3s; 496 | animation: slideToBottom 0.3s; } 497 | 498 | @-webkit-keyframes animateSuccessTip { 499 | 0% { 500 | width: 0; 501 | left: 1px; 502 | top: 19px; } 503 | 54% { 504 | width: 0; 505 | left: 1px; 506 | top: 19px; } 507 | 70% { 508 | width: 50px; 509 | left: -8px; 510 | top: 37px; } 511 | 84% { 512 | width: 17px; 513 | left: 21px; 514 | top: 48px; } 515 | 100% { 516 | width: 25px; 517 | left: 14px; 518 | top: 45px; } } 519 | 520 | @keyframes animateSuccessTip { 521 | 0% { 522 | width: 0; 523 | left: 1px; 524 | top: 19px; } 525 | 54% { 526 | width: 0; 527 | left: 1px; 528 | top: 19px; } 529 | 70% { 530 | width: 50px; 531 | left: -8px; 532 | top: 37px; } 533 | 84% { 534 | width: 17px; 535 | left: 21px; 536 | top: 48px; } 537 | 100% { 538 | width: 25px; 539 | left: 14px; 540 | top: 45px; } } 541 | 542 | @-webkit-keyframes animateSuccessLong { 543 | 0% { 544 | width: 0; 545 | right: 46px; 546 | top: 54px; } 547 | 65% { 548 | width: 0; 549 | right: 46px; 550 | top: 54px; } 551 | 84% { 552 | width: 55px; 553 | right: 0px; 554 | top: 35px; } 555 | 100% { 556 | width: 47px; 557 | right: 8px; 558 | top: 38px; } } 559 | 560 | @keyframes animateSuccessLong { 561 | 0% { 562 | width: 0; 563 | right: 46px; 564 | top: 54px; } 565 | 65% { 566 | width: 0; 567 | right: 46px; 568 | top: 54px; } 569 | 84% { 570 | width: 55px; 571 | right: 0px; 572 | top: 35px; } 573 | 100% { 574 | width: 47px; 575 | right: 8px; 576 | top: 38px; } } 577 | 578 | @-webkit-keyframes rotatePlaceholder { 579 | 0% { 580 | transform: rotate(-45deg); 581 | -webkit-transform: rotate(-45deg); } 582 | 5% { 583 | transform: rotate(-45deg); 584 | -webkit-transform: rotate(-45deg); } 585 | 12% { 586 | transform: rotate(-405deg); 587 | -webkit-transform: rotate(-405deg); } 588 | 100% { 589 | transform: rotate(-405deg); 590 | -webkit-transform: rotate(-405deg); } } 591 | 592 | @keyframes rotatePlaceholder { 593 | 0% { 594 | transform: rotate(-45deg); 595 | -webkit-transform: rotate(-45deg); } 596 | 5% { 597 | transform: rotate(-45deg); 598 | -webkit-transform: rotate(-45deg); } 599 | 12% { 600 | transform: rotate(-405deg); 601 | -webkit-transform: rotate(-405deg); } 602 | 100% { 603 | transform: rotate(-405deg); 604 | -webkit-transform: rotate(-405deg); } } 605 | 606 | .animateSuccessTip { 607 | -webkit-animation: animateSuccessTip 0.75s; 608 | animation: animateSuccessTip 0.75s; } 609 | 610 | .animateSuccessLong { 611 | -webkit-animation: animateSuccessLong 0.75s; 612 | animation: animateSuccessLong 0.75s; } 613 | 614 | .sa-icon.sa-success.animate::after { 615 | -webkit-animation: rotatePlaceholder 4.25s ease-in; 616 | animation: rotatePlaceholder 4.25s ease-in; } 617 | 618 | @-webkit-keyframes animateErrorIcon { 619 | 0% { 620 | transform: rotateX(100deg); 621 | -webkit-transform: rotateX(100deg); 622 | opacity: 0; } 623 | 100% { 624 | transform: rotateX(0deg); 625 | -webkit-transform: rotateX(0deg); 626 | opacity: 1; } } 627 | 628 | @keyframes animateErrorIcon { 629 | 0% { 630 | transform: rotateX(100deg); 631 | -webkit-transform: rotateX(100deg); 632 | opacity: 0; } 633 | 100% { 634 | transform: rotateX(0deg); 635 | -webkit-transform: rotateX(0deg); 636 | opacity: 1; } } 637 | 638 | .animateErrorIcon { 639 | -webkit-animation: animateErrorIcon 0.5s; 640 | animation: animateErrorIcon 0.5s; } 641 | 642 | @-webkit-keyframes animateXMark { 643 | 0% { 644 | transform: scale(0.4); 645 | -webkit-transform: scale(0.4); 646 | margin-top: 26px; 647 | opacity: 0; } 648 | 50% { 649 | transform: scale(0.4); 650 | -webkit-transform: scale(0.4); 651 | margin-top: 26px; 652 | opacity: 0; } 653 | 80% { 654 | transform: scale(1.15); 655 | -webkit-transform: scale(1.15); 656 | margin-top: -6px; } 657 | 100% { 658 | transform: scale(1); 659 | -webkit-transform: scale(1); 660 | margin-top: 0; 661 | opacity: 1; } } 662 | 663 | @keyframes animateXMark { 664 | 0% { 665 | transform: scale(0.4); 666 | -webkit-transform: scale(0.4); 667 | margin-top: 26px; 668 | opacity: 0; } 669 | 50% { 670 | transform: scale(0.4); 671 | -webkit-transform: scale(0.4); 672 | margin-top: 26px; 673 | opacity: 0; } 674 | 80% { 675 | transform: scale(1.15); 676 | -webkit-transform: scale(1.15); 677 | margin-top: -6px; } 678 | 100% { 679 | transform: scale(1); 680 | -webkit-transform: scale(1); 681 | margin-top: 0; 682 | opacity: 1; } } 683 | 684 | .animateXMark { 685 | -webkit-animation: animateXMark 0.5s; 686 | animation: animateXMark 0.5s; } 687 | 688 | @-webkit-keyframes pulseWarning { 689 | 0% { 690 | border-color: #F8D486; } 691 | 100% { 692 | border-color: #F8BB86; } } 693 | 694 | @keyframes pulseWarning { 695 | 0% { 696 | border-color: #F8D486; } 697 | 100% { 698 | border-color: #F8BB86; } } 699 | 700 | .pulseWarning { 701 | -webkit-animation: pulseWarning 0.75s infinite alternate; 702 | animation: pulseWarning 0.75s infinite alternate; } 703 | 704 | @-webkit-keyframes pulseWarningIns { 705 | 0% { 706 | background-color: #F8D486; } 707 | 100% { 708 | background-color: #F8BB86; } } 709 | 710 | @keyframes pulseWarningIns { 711 | 0% { 712 | background-color: #F8D486; } 713 | 100% { 714 | background-color: #F8BB86; } } 715 | 716 | .pulseWarningIns { 717 | -webkit-animation: pulseWarningIns 0.75s infinite alternate; 718 | animation: pulseWarningIns 0.75s infinite alternate; } 719 | 720 | @-webkit-keyframes rotate-loading { 721 | 0% { 722 | transform: rotate(0deg); } 723 | 100% { 724 | transform: rotate(360deg); } } 725 | 726 | @keyframes rotate-loading { 727 | 0% { 728 | transform: rotate(0deg); } 729 | 100% { 730 | transform: rotate(360deg); } } 731 | 732 | /* Internet Explorer 9 has some special quirks that are fixed here */ 733 | /* The icons are not animated. */ 734 | /* This file is automatically merged into sweet-alert.min.js through Gulp */ 735 | /* Error icon */ 736 | .sweet-alert .sa-icon.sa-error .sa-line.sa-left { 737 | -ms-transform: rotate(45deg) \9; } 738 | 739 | .sweet-alert .sa-icon.sa-error .sa-line.sa-right { 740 | -ms-transform: rotate(-45deg) \9; } 741 | 742 | /* Success icon */ 743 | .sweet-alert .sa-icon.sa-success { 744 | border-color: transparent\9; } 745 | 746 | .sweet-alert .sa-icon.sa-success .sa-line.sa-tip { 747 | -ms-transform: rotate(45deg) \9; } 748 | 749 | .sweet-alert .sa-icon.sa-success .sa-line.sa-long { 750 | -ms-transform: rotate(-45deg) \9; } 751 | 752 | /*! 753 | * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/) 754 | * Copyright 2015 Daniel Cardoso <@DanielCardoso> 755 | * Licensed under MIT 756 | */ 757 | .la-ball-fall, 758 | .la-ball-fall > div { 759 | position: relative; 760 | -webkit-box-sizing: border-box; 761 | -moz-box-sizing: border-box; 762 | box-sizing: border-box; } 763 | 764 | .la-ball-fall { 765 | display: block; 766 | font-size: 0; 767 | color: #fff; } 768 | 769 | .la-ball-fall.la-dark { 770 | color: #333; } 771 | 772 | .la-ball-fall > div { 773 | display: inline-block; 774 | float: none; 775 | background-color: currentColor; 776 | border: 0 solid currentColor; } 777 | 778 | .la-ball-fall { 779 | width: 54px; 780 | height: 18px; } 781 | 782 | .la-ball-fall > div { 783 | width: 10px; 784 | height: 10px; 785 | margin: 4px; 786 | border-radius: 100%; 787 | opacity: 0; 788 | -webkit-animation: ball-fall 1s ease-in-out infinite; 789 | -moz-animation: ball-fall 1s ease-in-out infinite; 790 | -o-animation: ball-fall 1s ease-in-out infinite; 791 | animation: ball-fall 1s ease-in-out infinite; } 792 | 793 | .la-ball-fall > div:nth-child(1) { 794 | -webkit-animation-delay: -200ms; 795 | -moz-animation-delay: -200ms; 796 | -o-animation-delay: -200ms; 797 | animation-delay: -200ms; } 798 | 799 | .la-ball-fall > div:nth-child(2) { 800 | -webkit-animation-delay: -100ms; 801 | -moz-animation-delay: -100ms; 802 | -o-animation-delay: -100ms; 803 | animation-delay: -100ms; } 804 | 805 | .la-ball-fall > div:nth-child(3) { 806 | -webkit-animation-delay: 0ms; 807 | -moz-animation-delay: 0ms; 808 | -o-animation-delay: 0ms; 809 | animation-delay: 0ms; } 810 | 811 | .la-ball-fall.la-sm { 812 | width: 26px; 813 | height: 8px; } 814 | 815 | .la-ball-fall.la-sm > div { 816 | width: 4px; 817 | height: 4px; 818 | margin: 2px; } 819 | 820 | .la-ball-fall.la-2x { 821 | width: 108px; 822 | height: 36px; } 823 | 824 | .la-ball-fall.la-2x > div { 825 | width: 20px; 826 | height: 20px; 827 | margin: 8px; } 828 | 829 | .la-ball-fall.la-3x { 830 | width: 162px; 831 | height: 54px; } 832 | 833 | .la-ball-fall.la-3x > div { 834 | width: 30px; 835 | height: 30px; 836 | margin: 12px; } 837 | 838 | /* 839 | * Animation 840 | */ 841 | @-webkit-keyframes ball-fall { 842 | 0% { 843 | opacity: 0; 844 | -webkit-transform: translateY(-145%); 845 | transform: translateY(-145%); } 846 | 10% { 847 | opacity: .5; } 848 | 20% { 849 | opacity: 1; 850 | -webkit-transform: translateY(0); 851 | transform: translateY(0); } 852 | 80% { 853 | opacity: 1; 854 | -webkit-transform: translateY(0); 855 | transform: translateY(0); } 856 | 90% { 857 | opacity: .5; } 858 | 100% { 859 | opacity: 0; 860 | -webkit-transform: translateY(145%); 861 | transform: translateY(145%); } } 862 | 863 | @-moz-keyframes ball-fall { 864 | 0% { 865 | opacity: 0; 866 | -moz-transform: translateY(-145%); 867 | transform: translateY(-145%); } 868 | 10% { 869 | opacity: .5; } 870 | 20% { 871 | opacity: 1; 872 | -moz-transform: translateY(0); 873 | transform: translateY(0); } 874 | 80% { 875 | opacity: 1; 876 | -moz-transform: translateY(0); 877 | transform: translateY(0); } 878 | 90% { 879 | opacity: .5; } 880 | 100% { 881 | opacity: 0; 882 | -moz-transform: translateY(145%); 883 | transform: translateY(145%); } } 884 | 885 | @-o-keyframes ball-fall { 886 | 0% { 887 | opacity: 0; 888 | -o-transform: translateY(-145%); 889 | transform: translateY(-145%); } 890 | 10% { 891 | opacity: .5; } 892 | 20% { 893 | opacity: 1; 894 | -o-transform: translateY(0); 895 | transform: translateY(0); } 896 | 80% { 897 | opacity: 1; 898 | -o-transform: translateY(0); 899 | transform: translateY(0); } 900 | 90% { 901 | opacity: .5; } 902 | 100% { 903 | opacity: 0; 904 | -o-transform: translateY(145%); 905 | transform: translateY(145%); } } 906 | 907 | @keyframes ball-fall { 908 | 0% { 909 | opacity: 0; 910 | -webkit-transform: translateY(-145%); 911 | -moz-transform: translateY(-145%); 912 | -o-transform: translateY(-145%); 913 | transform: translateY(-145%); } 914 | 10% { 915 | opacity: .5; } 916 | 20% { 917 | opacity: 1; 918 | -webkit-transform: translateY(0); 919 | -moz-transform: translateY(0); 920 | -o-transform: translateY(0); 921 | transform: translateY(0); } 922 | 80% { 923 | opacity: 1; 924 | -webkit-transform: translateY(0); 925 | -moz-transform: translateY(0); 926 | -o-transform: translateY(0); 927 | transform: translateY(0); } 928 | 90% { 929 | opacity: .5; } 930 | 100% { 931 | opacity: 0; 932 | -webkit-transform: translateY(145%); 933 | -moz-transform: translateY(145%); 934 | -o-transform: translateY(145%); 935 | transform: translateY(145%); } } 936 | -------------------------------------------------------------------------------- /src/main/webapp/resources/plugin/sweetalert/sweetalert.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t,n){"use strict";!function o(e,t,n){function a(s,l){if(!t[s]){if(!e[s]){var i="function"==typeof require&&require;if(!l&&i)return i(s,!0);if(r)return r(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return a(n?n:t)},c,c.exports,o,e,t,n)}return t[s].exports}for(var r="function"==typeof require&&require,s=0;s=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},i=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},u=function(e){e.style.opacity="",e.style.display="block"},c=function(e){if(e&&!e.length)return u(e);for(var t=0;t0?setTimeout(a,t):e.style.display="none"};o()},b=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},h=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)};a.hasClass=r,a.addClass=s,a.removeClass=l,a.escapeHtml=i,a._show=u,a.show=c,a._hide=d,a.hide=f,a.isDescendant=p,a.getTopMargin=m,a.fadeIn=v,a.fadeOut=y,a.fireClick=b,a.stopEventPropagation=h},{}],5:[function(t,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=t("./handle-dom"),s=t("./handle-swal-dom"),l=function(t,o,a){var l=t||e.event,i=l.keyCode||l.which,u=a.querySelector("button.confirm"),c=a.querySelector("button.cancel"),d=a.querySelectorAll("button[tabindex]");if(-1!==[9,13,32,27].indexOf(i)){for(var f=l.target||l.srcElement,p=-1,m=0;m"),i.innerHTML=e.html?e.text:(0,s.escapeHtml)(e.text||"").split("\n").join("
"),e.text&&(0,s.show)(i),e.customClass)(0,s.addClass)(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var d=t.getAttribute("data-custom-class");(0,s.removeClass)(t,d),t.setAttribute("data-custom-class","")}if((0,s.hide)(t.querySelectorAll(".sa-icon")),e.type&&!(0,a.isIE8)()){var f=function(){for(var o=!1,a=0;ao;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a};o.extend=a,o.hexToRgb=r,o.isIE8=s,o.logStr=l,o.colorLuminance=i},{}]},{},[1]),"function"==typeof define&&define.amd?define(function(){return sweetAlert}):"undefined"!=typeof module&&module.exports&&(module.exports=sweetAlert)}(window,document); -------------------------------------------------------------------------------- /src/test/java/cn/mccreefei/dao/UserDAOTest.java: -------------------------------------------------------------------------------- 1 | //package cn.mccreefei.dao; 2 | // 3 | //import cn.mccreefei.model.User; 4 | //import org.junit.Test; 5 | //import org.junit.runner.RunWith; 6 | //import org.springframework.beans.factory.annotation.Autowired; 7 | //import org.springframework.test.context.ContextConfiguration; 8 | //import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 | // 10 | //import static org.junit.Assert.*; 11 | // 12 | ///** 13 | // * Created by Administrator on 2017/5/10. 14 | // */ 15 | //@RunWith(SpringJUnit4ClassRunner.class) 16 | //@ContextConfiguration({"classpath:spring/spring-dao.xml"}) 17 | //public class UserDAOTest { 18 | // @Autowired 19 | // private UserDAO userDAO; 20 | // @Test 21 | // public void testQueryUser() throws Exception { 22 | // String name = "chris"; 23 | // String password = "123"; 24 | // User user = userDAO.queryUser(name, password); 25 | // System.out.println(user); 26 | // name = "mccreefei"; 27 | // user = userDAO.queryUser(name, password); 28 | // System.out.println(user); 29 | // } 30 | // 31 | // @Test 32 | // public void testQueryUserByName() throws Exception { 33 | // String name = "chris"; 34 | // User user = userDAO.queryUserByName(name); 35 | // assertNotNull(user); 36 | // System.out.println(user); 37 | // name = "jkasdhfjkashd"; 38 | // user = userDAO.queryUserByName(name); 39 | // assertNull(name + " exists!", user); 40 | // } 41 | // 42 | // @Test 43 | // public void testInsertUser() throws Exception { 44 | //// String name = "李四"; 45 | //// String password = "123456"; 46 | //// userDAO.insertUser(name, password); 47 | //// User user = userDAO.queryUser(name, password); 48 | //// System.out.println(user); 49 | // } 50 | // 51 | //} --------------------------------------------------------------------------------