├── lib ├── aopalliance-1.0.jar ├── tomcat │ └── servlet-api.jar ├── commons-logging-1.2.jar ├── dbcp │ ├── commons-dbcp2-2.1.1.jar │ ├── commons-pool2-2.4.2.jar │ └── geronimo-jta_1.1_spec-1.1.1.jar ├── fileupload │ ├── commons-io-2.6.jar │ └── commons-fileupload-1.3.3.jar ├── spring-aop-4.3.16.RELEASE.jar ├── spring-jms-4.3.16.RELEASE.jar ├── spring-orm-4.3.16.RELEASE.jar ├── spring-oxm-4.3.16.RELEASE.jar ├── spring-tx-4.3.16.RELEASE.jar ├── spring-web-4.3.16.RELEASE.jar ├── jackson │ ├── jackson-core-2.6.5.jar │ ├── jackson-jr-all-2.4.3.jar │ ├── jackson-databind-2.6.5.jar │ └── jackson-annotations-2.6.5.jar ├── spring-beans-4.3.16.RELEASE.jar ├── spring-core-4.3.16.RELEASE.jar ├── spring-jdbc-4.3.16.RELEASE.jar ├── spring-test-4.3.16.RELEASE.jar ├── spring-webmvc-4.3.16.RELEASE.jar ├── spring-aspects-4.3.16.RELEASE.jar ├── spring-context-4.3.16.RELEASE.jar ├── spring-expression-4.3.16.RELEASE.jar ├── spring-instrument-4.3.16.RELEASE.jar ├── spring-messaging-4.3.16.RELEASE.jar ├── spring-websocket-4.3.16.RELEASE.jar ├── spring-context-support-4.3.16.RELEASE.jar ├── spring-webmvc-portlet-4.3.16.RELEASE.jar ├── spring-instrument-tomcat-4.3.16.RELEASE.jar └── mysql-connector-java-5.1.40 │ └── mysql-connector-java-5.1.40.jar ├── web ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── WEB-INF │ └── web.xml ├── logout.jsp ├── form.jsp ├── js │ ├── common │ │ └── ajaxfunc.js │ ├── user │ │ ├── register.js │ │ └── login.js │ ├── ajax_test │ │ └── ajax_test.js │ └── message │ │ └── message.js ├── ajax.jsp ├── upload_file.jsp ├── css │ ├── user │ │ └── user_normal.css │ └── bootstrap │ │ ├── bootstrap-theme.min.css │ │ └── font-awesome.min.css ├── register.jsp ├── login.jsp └── index.jsp ├── .gitignore ├── src └── cn │ └── nuaa │ └── tomax │ ├── service │ ├── IMessageService.java │ ├── IUserService.java │ ├── IHelloService.java │ └── impl │ │ ├── MessageServiceImpl.java │ │ ├── HelloServiceImpl.java │ │ └── UserServiceImpl.java │ ├── dao │ ├── IMessageDao.java │ ├── IUserDao.java │ ├── impl │ │ ├── UserDaoImpl.java │ │ ├── MessageDaoImpl.java │ │ └── HelloDaoImpl.java │ ├── IHelloDao.java │ └── DaoHelper.java │ ├── entity │ ├── FormEntity.java │ ├── HelloEntity.java │ ├── ResultCause.java │ ├── GoodEntity.java │ ├── UserEntity.java │ └── MessageEntity.java │ ├── configuration │ ├── RootConfig.java │ ├── WebInitializer.java │ ├── AppConfig.java │ └── WebConfig.java │ └── controller │ ├── SuperAction.java │ ├── MessageController.java │ ├── HelloController.java │ ├── UserController.java │ ├── FileUploadController.java │ └── HelloWorldController.java ├── README.md ├── blogs ├── 问题跟踪和更新说明.md ├── README.md ├── mvc.md ├── 开发环境搭建.md ├── 前后端数据交互.md ├── 增加数据库支持.md ├── Helloworld.md ├── 登录注册功能的实现.md └── 简单留言功能的实现.md └── sql └── dpd.sql /lib/aopalliance-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/aopalliance-1.0.jar -------------------------------------------------------------------------------- /lib/tomcat/servlet-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/tomcat/servlet-api.jar -------------------------------------------------------------------------------- /web/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /lib/commons-logging-1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/commons-logging-1.2.jar -------------------------------------------------------------------------------- /lib/dbcp/commons-dbcp2-2.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/dbcp/commons-dbcp2-2.1.1.jar -------------------------------------------------------------------------------- /lib/dbcp/commons-pool2-2.4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/dbcp/commons-pool2-2.4.2.jar -------------------------------------------------------------------------------- /lib/fileupload/commons-io-2.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/fileupload/commons-io-2.6.jar -------------------------------------------------------------------------------- /lib/spring-aop-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-aop-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-jms-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-jms-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-orm-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-orm-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-oxm-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-oxm-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-tx-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-tx-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-web-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-web-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /web/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /web/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /lib/jackson/jackson-core-2.6.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/jackson/jackson-core-2.6.5.jar -------------------------------------------------------------------------------- /lib/jackson/jackson-jr-all-2.4.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/jackson/jackson-jr-all-2.4.3.jar -------------------------------------------------------------------------------- /lib/spring-beans-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-beans-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-core-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-core-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-jdbc-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-jdbc-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-test-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-test-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-webmvc-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-webmvc-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /web/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /lib/jackson/jackson-databind-2.6.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/jackson/jackson-databind-2.6.5.jar -------------------------------------------------------------------------------- /lib/spring-aspects-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-aspects-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-context-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-context-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/dbcp/geronimo-jta_1.1_spec-1.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/dbcp/geronimo-jta_1.1_spec-1.1.1.jar -------------------------------------------------------------------------------- /lib/jackson/jackson-annotations-2.6.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/jackson/jackson-annotations-2.6.5.jar -------------------------------------------------------------------------------- /lib/spring-expression-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-expression-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-instrument-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-instrument-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-messaging-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-messaging-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-websocket-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-websocket-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/fileupload/commons-fileupload-1.3.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/fileupload/commons-fileupload-1.3.3.jar -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /lib/spring-context-support-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-context-support-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /lib/spring-webmvc-portlet-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-webmvc-portlet-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/web/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /lib/spring-instrument-tomcat-4.3.16.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/spring-instrument-tomcat-4.3.16.RELEASE.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Example user template template 3 | ### Example user template 4 | 5 | # IntelliJ project files 6 | out 7 | gen 8 | -------------------------------------------------------------------------------- /lib/mysql-connector-java-5.1.40/mysql-connector-java-5.1.40.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingToMax/DesignPatternCourseDesign/HEAD/lib/mysql-connector-java-5.1.40/mysql-connector-java-5.1.40.jar -------------------------------------------------------------------------------- /web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | index.jsp 8 | 9 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/IMessageService.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service; 2 | 3 | import cn.nuaa.tomax.entity.MessageEntity; 4 | import cn.nuaa.tomax.entity.ResultCause; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @Author: ToMax 10 | * @Description: 11 | * @Date: Created in 2018/5/5 18:41 12 | */ 13 | public interface IMessageService { 14 | public ResultCause addMessage(MessageEntity msg); 15 | public List getMsgs(); 16 | } 17 | -------------------------------------------------------------------------------- /web/logout.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/2/23 5 | Time: 20:28 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | 注销 12 | <% 13 | session.invalidate(); 14 | out.print(""); 15 | %> 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/form.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/4/29 5 | Time: 23:01 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | 表单提交 12 | 13 | 14 | 15 | 姓名 16 | 签名 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/js/common/ajaxfunc.js: -------------------------------------------------------------------------------- 1 | function post(url,param,callback){ 2 | $.ajax({ 3 | url : url, 4 | type : 'post', 5 | data : param, 6 | dataType : 'json', 7 | timeout : 100000, 8 | success : function(data) { 9 | callback(data); 10 | }, 11 | error : function(e) { 12 | console.log("ERROR: ", e); 13 | }, 14 | done : function(e) { 15 | console.log("DONE"); 16 | enableSearchButton(true); 17 | }, 18 | complete : function() { 19 | } 20 | }); 21 | } -------------------------------------------------------------------------------- /web/js/user/register.js: -------------------------------------------------------------------------------- 1 | function go_to_login() { 2 | window.location.href = "login.jsp" 3 | } 4 | 5 | $("#reg_btn").on('click',function () { 6 | var username = $('#username').val() 7 | var password = $('#password').val() 8 | var param = {'name':username,'password':password} 9 | post('user/register',param,function (result) { 10 | if (result.code == '200'){ 11 | alert(result.desc) 12 | window.location.href = "login.jsp" 13 | }else { 14 | alert(result.desc) 15 | window.location.href = "register.jsp" 16 | } 17 | }) 18 | }) -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/IMessageDao.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao; 2 | 3 | import cn.nuaa.tomax.entity.MessageEntity; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @Author: ToMax 9 | * @Description: 10 | * @Date: Created in 2018/5/5 18:37 11 | */ 12 | public interface IMessageDao { 13 | /** 14 | * 新增留言 15 | * @param sql 16 | * @param message 17 | */ 18 | public void saveMessage(String sql, MessageEntity message); 19 | 20 | /** 21 | * 获取留言 22 | * @param sql 23 | * @param keys 24 | * @return 25 | */ 26 | public List listMsgs(String sql, Object[] keys); 27 | } 28 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/IUserDao.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao; 2 | 3 | import cn.nuaa.tomax.entity.UserEntity; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @Author: ToMax 9 | * @Description: 10 | * @Date: Created in 2018/5/4 22:25 11 | */ 12 | public interface IUserDao { 13 | /** 14 | * 新增用户 15 | * @param sql 16 | * @param user 17 | */ 18 | public void saveUser(String sql, UserEntity user); 19 | 20 | /** 21 | * 根据条件获取用户列表 22 | * @param sql 23 | * @param keys 24 | * @return 25 | */ 26 | public List listUsers(String sql, Object[] keys); 27 | } 28 | -------------------------------------------------------------------------------- /web/js/ajax_test/ajax_test.js: -------------------------------------------------------------------------------- 1 | $("#send-ajax").on('click',function () { 2 | var param = {'name':'ToMax','signature':'hhh'} 3 | post('ajax_test',param,function (data) { 4 | alert(data.desc) 5 | }) 6 | }); 7 | 8 | $("#display-list").on('click',function () { 9 | post('get_list',[],function (data) { 10 | liHtml = "" 11 | for (var i = 0; i" 13 | liHtml += "code : "+data[i].code 14 | liHtml += ", desc : "+data[i].desc 15 | liHtml += "" 16 | } 17 | $("#list").html(liHtml) 18 | }) 19 | }); -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/FormEntity.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | /** 4 | * @Author: ToMax 5 | * @Description: 6 | * @Date: Created in 2018/4/30 9:55 7 | */ 8 | public class FormEntity { 9 | 10 | private String name; 11 | private String signature; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public String getSignature() { 22 | return signature; 23 | } 24 | 25 | public void setSignature(String signature) { 26 | this.signature = signature; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/ajax.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/4/30 5 | Time: 10:55 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | ajax 12 | 13 | 14 | 发送ajax 请求 15 | 显示列表 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/configuration/RootConfig.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.configuration; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.FilterType; 6 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 7 | 8 | /** 9 | * @Author: ToMax 10 | * @Description: 11 | * @Date: Created in 2018/4/19 17:05 12 | */ 13 | @Configuration 14 | @ComponentScan(basePackages = {"cn.nuaa.tomax"}, 15 | excludeFilters = { 16 | @ComponentScan.Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)}) 17 | public class RootConfig { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/SuperAction.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.ModelAttribute; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | /** 9 | * @Author: ToMax 10 | * @Description: 11 | * @Date: Created in 2018/5/5 15:06 12 | */ 13 | @Controller 14 | public class SuperAction { 15 | protected HttpServletRequest request; 16 | protected HttpServletResponse response; 17 | 18 | @ModelAttribute 19 | public void setReqAndRes(HttpServletRequest request, HttpServletResponse response){ 20 | this.request = request; 21 | this.response = response; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/impl/UserDaoImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao.impl; 2 | 3 | import cn.nuaa.tomax.dao.DaoHelper; 4 | import cn.nuaa.tomax.dao.IUserDao; 5 | import cn.nuaa.tomax.entity.UserEntity; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @Author: ToMax 12 | * @Description: 13 | * @Date: Created in 2018/5/4 22:29 14 | */ 15 | @Repository 16 | public class UserDaoImpl extends DaoHelper implements IUserDao{ 17 | @Override 18 | public void saveUser(String sql, UserEntity user) { 19 | this.insertByBean(sql,user); 20 | } 21 | 22 | @Override 23 | public List listUsers(String sql, Object[] keys) { 24 | return this.query(sql,keys,UserEntity.class); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/IUserService.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service; 2 | 3 | import cn.nuaa.tomax.entity.ResultCause; 4 | import cn.nuaa.tomax.entity.UserEntity; 5 | 6 | /** 7 | * @Author: ToMax 8 | * @Description: 9 | * @Date: Created in 2018/5/4 22:44 10 | */ 11 | public interface IUserService { 12 | /** 13 | * 登录验证 14 | * @param name 15 | * @param password 16 | * @return 17 | */ 18 | public ResultCause checkUser(String name, String password); 19 | 20 | /** 21 | * 用户注册 22 | * @param user 23 | * @return 24 | */ 25 | public ResultCause registerUser(UserEntity user); 26 | 27 | /** 28 | * 通过用户名获取用户信息 29 | * @param name 30 | * @return 31 | */ 32 | public UserEntity getUserInfo(String name); 33 | } 34 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/impl/MessageDaoImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao.impl; 2 | 3 | import cn.nuaa.tomax.dao.DaoHelper; 4 | import cn.nuaa.tomax.dao.IMessageDao; 5 | import cn.nuaa.tomax.entity.MessageEntity; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @Author: ToMax 12 | * @Description: 13 | * @Date: Created in 2018/5/5 18:39 14 | */ 15 | @Repository 16 | public class MessageDaoImpl extends DaoHelper implements IMessageDao{ 17 | @Override 18 | public void saveMessage(String sql, MessageEntity message) { 19 | this.insertByBean(sql,message); 20 | } 21 | 22 | @Override 23 | public List listMsgs(String sql, Object[] keys) { 24 | return this.query(sql,keys,MessageEntity.class); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/HelloEntity.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | /** 4 | * @Author: ToMax 5 | * @Description: 6 | * @Date: Created in 2018/4/30 23:16 7 | */ 8 | public class HelloEntity { 9 | private String name; 10 | private String signature; 11 | public HelloEntity(){} 12 | 13 | public HelloEntity(String name, String signature) { 14 | this.name = name; 15 | this.signature = signature; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | 26 | public String getSignature() { 27 | return signature; 28 | } 29 | 30 | public void setSignature(String signature) { 31 | this.signature = signature; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /web/upload_file.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/5/7 5 | Time: 15:08 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | File upload 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DesignPatternDemo 2 | 基于Spring MVC的demo,包含几篇介绍web开发的博客,用于设计模式课程设计 3 | 4 | 本课设demo实现技术栈非常落后,效率极差,建议学习使用spring boot完成相应的开发(后续有空会更新为spring boot的内容)。 5 | 6 | [第一篇博客地址](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 7 | 8 | + blogs目录下为博客,点开目录的README.md即为博客目录 9 | + sql目录下放了项目中出现表的sql文件 10 | + [演示地址](http://tomax.xin/dpd) 11 | 12 | 注: 13 | master分支用于博客的演示 14 | ToMax分支上会持续更新一些新的功能支持 15 | 16 | ## 项目配置 17 | 18 | ### 环境要求 19 | 20 | + jdk8 21 | + tomcat8 22 | + mysql 23 | + intellij idea 24 | 25 | ### 配置工作 26 | 27 | clone 代码后在intellij 中打开,需要配置`tomcat`,新增tomcat为本地tomcat地址 28 | 29 | mysql 导入`sql`目录下的`dpd.sql` 30 | 31 | 启动项目 32 | 33 | 更多的细节查看[地址1](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md) [地址2](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/Helloworld.md) 34 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/ResultCause.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | /** 4 | * @Author: ToMax 5 | * @Description: 6 | * @Date: Created in 2018/4/24 23:43 7 | */ 8 | public class ResultCause { 9 | 10 | public static final String SUCCESS_CODE = "200"; 11 | public static final String FAIL_CODE = "400"; 12 | 13 | private String code; 14 | private String desc; 15 | 16 | public ResultCause() {} 17 | 18 | public ResultCause(String code, String desc) { 19 | this.code = code; 20 | this.desc = desc; 21 | } 22 | 23 | public String getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(String code) { 28 | this.code = code; 29 | } 30 | 31 | public String getDesc() { 32 | return desc; 33 | } 34 | 35 | public void setDesc(String desc) { 36 | this.desc = desc; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/IHelloService.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service; 2 | 3 | import cn.nuaa.tomax.entity.HelloEntity; 4 | import cn.nuaa.tomax.entity.ResultCause; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @Author: ToMax 10 | * @Description: 11 | * @Date: Created in 2018/4/30 23:59 12 | */ 13 | public interface IHelloService { 14 | /** 15 | * 增加hello数据 16 | * @param bean 17 | * @return 18 | */ 19 | public ResultCause addHello(HelloEntity bean); 20 | 21 | /** 22 | * 获取hello数据 23 | * @return 24 | */ 25 | public List listHello(); 26 | 27 | /** 28 | * 更新hello数据,更新对应name的signature 29 | * @param bean 30 | * @return 31 | */ 32 | 33 | public ResultCause updateHelloData(HelloEntity bean); 34 | 35 | /** 36 | * 删除指定name的hello数据 37 | * @param name 38 | * @return 39 | */ 40 | public ResultCause removeHelloData(String name); 41 | } 42 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/GoodEntity.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | /** 4 | * @Author: ToMax 5 | * @Description: 6 | * @Date: Created in 2018/4/24 0:10 7 | */ 8 | public class GoodEntity { 9 | private long id; 10 | private String name; 11 | private float price; 12 | 13 | public GoodEntity() { 14 | 15 | } 16 | 17 | public GoodEntity(long id, String name, float price) { 18 | this.id = id; 19 | this.name = name; 20 | this.price = price; 21 | } 22 | 23 | public long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(long id) { 28 | this.id = id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | 39 | public float getPrice() { 40 | return price; 41 | } 42 | 43 | public void setPrice(float price) { 44 | this.price = price; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /web/css/user/user_normal.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 200px; 3 | padding-bottom: 40px; 4 | background-color: #eee; 5 | } 6 | 7 | .form-signin { 8 | max-width: 420px; 9 | padding: 15px; 10 | margin: 0 auto; 11 | } 12 | .form-signin .form-signin-heading, 13 | .form-signin .checkbox { 14 | margin-bottom: 10px; 15 | } 16 | .form-signin .checkbox { 17 | font-weight: normal; 18 | } 19 | .form-signin .form-control { 20 | position: relative; 21 | height: auto; 22 | -webkit-box-sizing: border-box; 23 | -moz-box-sizing: border-box; 24 | box-sizing: border-box; 25 | padding: 10px; 26 | font-size: 16px; 27 | } 28 | .form-signin .form-control:focus { 29 | z-index: 2; 30 | } 31 | .form-signin input[type="text"] { 32 | margin-bottom: -1px; 33 | border-bottom-right-radius: 0; 34 | border-bottom-left-radius: 0; 35 | } 36 | .form-signin input[type="password"] { 37 | margin-bottom: 10px; 38 | border-top-left-radius: 0; 39 | border-top-right-radius: 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/IHelloDao.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao; 2 | 3 | import cn.nuaa.tomax.entity.HelloEntity; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @Author: ToMax 9 | * @Description: 10 | * @Date: Created in 2018/4/30 23:14 11 | */ 12 | public interface IHelloDao { 13 | /** 14 | * 保存单个HelloEntity对象 15 | * @param sql 保存sql语句 16 | * @param bean HelloEntity对象 17 | */ 18 | public void saveHello(String sql, HelloEntity bean); 19 | 20 | /** 21 | * 查询满足一定条件的hello列表 22 | * @param sql 查询sql语句 23 | * @param keys 查询中需要用的约束值数组 24 | * @return 25 | */ 26 | public List listHello(String sql, Object[] keys); 27 | 28 | /** 29 | * 更新满足一定条件的hello数据 30 | * @param sql 31 | * @param keys 32 | */ 33 | public void updateHelloData(String sql, Object[] keys); 34 | 35 | /** 36 | * 删除满足一定条件的hello数据 37 | * @param sql 38 | * @param keys 39 | */ 40 | public void removeHelloData(String sql, Object[] keys); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | import java.sql.Timestamp; 4 | 5 | /** 6 | * @Author: ToMax 7 | * @Description: 8 | * @Date: Created in 2018/5/4 22:23 9 | */ 10 | public class UserEntity { 11 | private Integer id; 12 | private String name; 13 | private String password; 14 | private Timestamp time; 15 | 16 | public Integer getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Integer 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 Timestamp getTime() { 41 | return time; 42 | } 43 | 44 | public void setTime(Timestamp time) { 45 | this.time = time; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/impl/HelloDaoImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao.impl; 2 | 3 | import cn.nuaa.tomax.dao.DaoHelper; 4 | import cn.nuaa.tomax.dao.IHelloDao; 5 | import cn.nuaa.tomax.entity.HelloEntity; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @Author: ToMax 12 | * @Description: 13 | * @Date: Created in 2018/4/30 23:25 14 | */ 15 | @Repository 16 | public class HelloDaoImpl extends DaoHelper implements IHelloDao { 17 | @Override 18 | public void saveHello(String sql, HelloEntity bean) { 19 | this.insertByBean(sql,bean); 20 | } 21 | 22 | @Override 23 | public List listHello(String sql, Object[] keys) { 24 | return this.query(sql,keys,HelloEntity.class); 25 | } 26 | 27 | @Override 28 | public void updateHelloData(String sql, Object[] keys) { 29 | this.update(sql,keys); 30 | } 31 | 32 | @Override 33 | public void removeHelloData(String sql, Object[] keys) { 34 | this.update(sql,keys); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /web/js/message/message.js: -------------------------------------------------------------------------------- 1 | getMsgListRequest() 2 | 3 | function getMsgListRequest() { 4 | post('msg/getMsgs',[],function (result) { 5 | listHtml = '' 6 | for (var i = 0; i < result.length; i++){ 7 | listHtml += '' 8 | listHtml += ''+result[i].name+'' 9 | listHtml += result[i].content 10 | listHtml += '' 11 | } 12 | $('#msg_list').html(listHtml) 13 | }) 14 | } 15 | 16 | $('#msg_btn').on('click',function () { 17 | if (userId == -1){ 18 | alert('留言请先登录') 19 | }else { 20 | var content = $('#msg_con').val() 21 | var param = {'content':content,'userId':userId} 22 | post('msg/addMsg',param,function (result) { 23 | alert(result.desc) 24 | getMsgListRequest() 25 | }) 26 | } 27 | }) 28 | 29 | $('#log').on('click',function () { 30 | if (userId == -1){ 31 | window.location.href = 'login.jsp' 32 | }else { 33 | window.location.href = 'logout.jsp' 34 | } 35 | }) -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/MessageController.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import cn.nuaa.tomax.entity.MessageEntity; 4 | import cn.nuaa.tomax.entity.ResultCause; 5 | import cn.nuaa.tomax.service.IMessageService; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * @Author: ToMax 16 | * @Description: 17 | * @Date: Created in 2018/5/5 18:55 18 | */ 19 | @Controller 20 | @RequestMapping("/msg") 21 | public class MessageController { 22 | @Resource 23 | private IMessageService messageService; 24 | 25 | @RequestMapping(value = "/addMsg", method = {RequestMethod.GET,RequestMethod.POST}) 26 | public @ResponseBody 27 | ResultCause addMsg(MessageEntity msg){ 28 | return messageService.addMessage(msg); 29 | } 30 | 31 | @RequestMapping(value = "/getMsgs", method = {RequestMethod.GET,RequestMethod.POST}) 32 | public @ResponseBody 33 | List getMsgs(){ 34 | return messageService.getMsgs(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/entity/MessageEntity.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.entity; 2 | 3 | import java.sql.Timestamp; 4 | 5 | /** 6 | * @Author: ToMax 7 | * @Description: 8 | * @Date: Created in 2018/5/5 18:35 9 | */ 10 | public class MessageEntity { 11 | private Integer id; 12 | private Integer userId; 13 | private String name; 14 | private String content; 15 | private Timestamp time; 16 | 17 | public Integer getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Integer id) { 22 | this.id = id; 23 | } 24 | 25 | public Integer getUserId() { 26 | return userId; 27 | } 28 | 29 | public void setUserId(Integer userId) { 30 | this.userId = userId; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public String getContent() { 42 | return content; 43 | } 44 | 45 | public void setContent(String content) { 46 | this.content = content; 47 | } 48 | 49 | public Timestamp getTime() { 50 | return time; 51 | } 52 | 53 | public void setTime(Timestamp time) { 54 | this.time = time; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/configuration/WebInitializer.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.configuration; 2 | 3 | import org.springframework.web.WebApplicationInitializer; 4 | import org.springframework.web.filter.CharacterEncodingFilter; 5 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 6 | 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.ServletException; 9 | 10 | /** 11 | * @Author: ToMax 12 | * @Description: 13 | * @Date: Created in 2018/4/19 16:47 14 | */ 15 | public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{ 16 | @Override 17 | protected Class>[] getRootConfigClasses() { 18 | return new Class[] { RootConfig.class }; 19 | } 20 | 21 | @Override 22 | protected Class>[] getServletConfigClasses() { 23 | return new Class>[]{ WebConfig.class}; 24 | } 25 | 26 | @Override 27 | protected String[] getServletMappings() { 28 | return new String[] { "/" }; 29 | } 30 | 31 | @Override 32 | public void onStartup(ServletContext servletContext) throws ServletException { 33 | super.onStartup(servletContext); 34 | servletContext.addFilter("name", new CharacterEncodingFilter("UTF-8", true)) 35 | .addMappingForUrlPatterns(null, false, "/*"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/impl/MessageServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service.impl; 2 | 3 | import cn.nuaa.tomax.dao.IMessageDao; 4 | import cn.nuaa.tomax.entity.MessageEntity; 5 | import cn.nuaa.tomax.entity.ResultCause; 6 | import cn.nuaa.tomax.service.IMessageService; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.Resource; 10 | import java.sql.Timestamp; 11 | import java.util.List; 12 | 13 | /** 14 | * @Author: ToMax 15 | * @Description: 16 | * @Date: Created in 2018/5/5 18:42 17 | */ 18 | @Service 19 | public class MessageServiceImpl implements IMessageService{ 20 | @Resource 21 | private IMessageDao messageDao; 22 | @Override 23 | public ResultCause addMessage(MessageEntity msg) { 24 | msg.setTime(new Timestamp(System.currentTimeMillis())); 25 | String sql = "insert into message (user_id,content,time) values (:userId,:content,:time)"; 26 | messageDao.saveMessage(sql,msg); 27 | return new ResultCause(ResultCause.SUCCESS_CODE,"添加消息成功"); 28 | } 29 | 30 | @Override 31 | public List getMsgs() { 32 | String sql = "select m.id,m.user_id,m.content,m.time,u.name from message as m inner join user as u on (m.user_id = u.id) order by m.time desc"; 33 | return messageDao.listMsgs(sql,new Object[]{}); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/configuration/AppConfig.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.configuration; 2 | 3 | import org.apache.commons.dbcp2.BasicDataSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.jdbc.core.JdbcTemplate; 8 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 9 | 10 | import javax.sql.DataSource; 11 | 12 | /** 13 | * @Author: ToMax 14 | * @Description: 15 | * @Date: Created in 2018/4/30 16:51 16 | */ 17 | @Configuration 18 | @ComponentScan("cn.nuaa.tomax") 19 | public class AppConfig { 20 | @Bean 21 | public BasicDataSource dataSource(){ 22 | BasicDataSource ds = new BasicDataSource(); 23 | ds.setDriverClassName("com.mysql.jdbc.Driver"); 24 | ds.setUrl("jdbc:mysql://localhost:3306/design_pattern?useUnicode=true&characterEncoding=utf-8&useSSL=true"); 25 | ds.setUsername("root"); 26 | ds.setPassword(""); 27 | ds.setInitialSize(3); 28 | ds.setMaxTotal(200); 29 | ds.setMaxIdle(50); 30 | ds.setMinIdle(5); 31 | return ds; 32 | } 33 | 34 | @Bean 35 | public JdbcTemplate jdbcTemplate(DataSource dataSource){ 36 | return new JdbcTemplate(dataSource); 37 | } 38 | 39 | @Bean 40 | public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource){ 41 | return new NamedParameterJdbcTemplate(dataSource); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/HelloController.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import cn.nuaa.tomax.entity.HelloEntity; 4 | import cn.nuaa.tomax.entity.ResultCause; 5 | import cn.nuaa.tomax.service.IHelloService; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * @Author: ToMax 16 | * @Description: 17 | * @Date: Created in 2018/5/1 19:58 18 | */ 19 | @Controller 20 | @RequestMapping("/hello") 21 | public class HelloController { 22 | 23 | @Resource 24 | private IHelloService helloService; 25 | 26 | @RequestMapping(value = "/addHello", method = RequestMethod.GET) 27 | public @ResponseBody 28 | ResultCause addHelloData(HelloEntity hello){ 29 | return helloService.addHello(hello); 30 | } 31 | 32 | @RequestMapping(value = "/getHelloList", method = RequestMethod.GET) 33 | public @ResponseBody 34 | List getHelloList(){ 35 | return helloService.listHello(); 36 | } 37 | 38 | @RequestMapping(value = "/updateHello", method = RequestMethod.GET) 39 | public @ResponseBody 40 | ResultCause updateHello(HelloEntity hello){ 41 | return helloService.updateHelloData(hello); 42 | } 43 | 44 | @RequestMapping(value = "/deleteHello", method = RequestMethod.GET) 45 | public @ResponseBody 46 | ResultCause deleteHelloData(String name){ 47 | return helloService.removeHelloData(name); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /blogs/问题跟踪和更新说明.md: -------------------------------------------------------------------------------- 1 | # 问题解答 2 | 3 | **Author : ToMax** 4 | 5 | > 用于解决一些博客中没有注意到的问题,以及后续一些功能增加的说明,将持续更新 6 | 7 | ## 2018.6.1 8 | 9 | 关于之前登录注册中点击提交按钮会出现没有反应,并且地址栏中的地址后出现了一堆输入的`token`的问题,是因为`button`的默认`type`搞成了`submit`,所以需要设置`button`的`type="button"` 10 | ## 2018.5.7 11 | 12 | + 增加了对文件上传功能的支持 13 | 14 | 主要涉及更新的文件为`cn.nuaa.tomax.configuration.WebConfig`,增加了一项配置 15 | 增加了依赖`lib/fileupload`,其中两个库,`apache-commons-fileupload`,`apache-commons-io`,需要分别添加 16 | 增加了示例,文件上传的demo为`cn.nuaa.tomax.controller.FileUploadController`以及`web.upload_file.jsp` 17 | 18 | 由于未添加相关依赖时,文件上传功能的配置会导致服务器500错误,故取消master分支上的相关配置,相应更新会在ToMax分支上继续维护 19 | 20 | + @Resource不可用的问题 21 | 22 | `@Resource`注解是jdk1.6开始支持的,但是在目前有同学出现无法使用的情况,而且状况不同,暂时未找到原因 23 | 如果出现`@Resource`注解不可用,可以尝试换成`@Autowired`注解,这个注解是`spring`种定义的,所以基本是不会有问题的。 24 | 关于二者的区别是,在作用上基本相同,可以互相替代,其中`@Resource`注解是优先按照名称注入,`@Autowired`是默认按照类型注入的。`@Autowired`需要配合`@Qualifier`注解才可以实现按照名称注入,`@Resource`是先寻找可以用名称注入的`bean`,找不到才会按照类型注入。 25 | 26 | ## 2018.5.6 27 | 28 | + 对于博客中加载模糊的图片 29 | 30 | 图片都是放在我的服务器中,到github上加载的时候部分图片会被处理的很模糊,大部分不会影响进程,如果实在需要看图片,方法也很简单,F12打开浏览器(建议是chrome)的开发者模式,会出现一个k开发者操作的工作台,在工作台的边沿有`Elemnts`、`Console`等tab项,旁边有一个鼠标箭头的icon,点击这个icon之后在页面中再点击模糊的图片,工作台中会自动定位到该页面元素下,检查img标签,复制`data-canonical-src`属性后的以`http://tomax.xin`开头的图片链接,在地址栏输入该链接就可以查看清晰图。 31 | 32 | + 5.7之前开始可以重新复制一次`configuration/WebInitializer` 33 | 34 | 解决了表单提交中文出现乱码的问题 35 | 36 | ## 2018.5.4 37 | + 对于直接复制博客中代码后,在IDE中代码区出现许多代码标红 38 | 39 | 是因为对于一些函数没有`import`相应的依赖,在博客中部分代码没有在类的上方加上`import ...`或者包名中含有`.tomax.`的字段与个人的包路径不对 40 | 41 | 解决方法: 将类上方标红的`import ...`删除,然后将光标移至标红的函数处,快捷键`Alt+insert`,然后会有提示解决问题方案,通常是选择`import class`那一项 42 | 43 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 44 | 45 | 46 | 47 | > 如果有帮助的话,来颗star吧 -------------------------------------------------------------------------------- /sql/dpd.sql: -------------------------------------------------------------------------------- 1 | /* 2 | SQLyog Ultimate v11.24 (32 bit) 3 | MySQL - 5.6.15 : Database - design_pattern 4 | ********************************************************************* 5 | */ 6 | 7 | /*!40101 SET NAMES utf8 */; 8 | 9 | /*!40101 SET SQL_MODE=''*/; 10 | 11 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 12 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 13 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 14 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 15 | CREATE DATABASE /*!32312 IF NOT EXISTS*/`design_pattern` /*!40100 DEFAULT CHARACTER SET utf8 */; 16 | 17 | USE `design_pattern`; 18 | 19 | /*Table structure for table `hello` */ 20 | 21 | DROP TABLE IF EXISTS `hello`; 22 | 23 | CREATE TABLE `hello` ( 24 | `name` varchar(32) DEFAULT NULL, 25 | `signature` varchar(32) DEFAULT NULL 26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 27 | 28 | /*Table structure for table `message` */ 29 | 30 | DROP TABLE IF EXISTS `message`; 31 | 32 | CREATE TABLE `message` ( 33 | `id` int(11) NOT NULL AUTO_INCREMENT, 34 | `user_id` int(11) DEFAULT NULL, 35 | `content` varchar(128) DEFAULT NULL, 36 | `time` datetime DEFAULT NULL, 37 | PRIMARY KEY (`id`) 38 | ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; 39 | 40 | /*Table structure for table `user` */ 41 | 42 | DROP TABLE IF EXISTS `user`; 43 | 44 | CREATE TABLE `user` ( 45 | `id` int(11) NOT NULL AUTO_INCREMENT, 46 | `name` varchar(64) DEFAULT NULL, 47 | `password` varchar(32) DEFAULT NULL, 48 | `time` datetime DEFAULT NULL, 49 | PRIMARY KEY (`id`) 50 | ) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8; 51 | 52 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 53 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 54 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 55 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 56 | -------------------------------------------------------------------------------- /web/register.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/2/20 5 | Time: 11:25 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import cn.nuaa.tomax.entity.ResultCause; 4 | import cn.nuaa.tomax.entity.UserEntity; 5 | import cn.nuaa.tomax.service.IUserService; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.annotation.Resource; 12 | import javax.servlet.http.Cookie; 13 | import javax.servlet.http.HttpServletResponse; 14 | import javax.servlet.http.HttpSession; 15 | import java.io.IOException; 16 | 17 | /** 18 | * @Author: ToMax 19 | * @Description: 20 | * @Date: Created in 2018/5/4 23:41 21 | */ 22 | @Controller 23 | @RequestMapping("/user") 24 | public class UserController extends SuperAction{ 25 | @Resource 26 | private IUserService userService; 27 | 28 | @RequestMapping(value = "/login", method = {RequestMethod.GET,RequestMethod.POST}) 29 | public @ResponseBody 30 | ResultCause login(String name, String password) throws IOException { 31 | ResultCause result = userService.checkUser(name,password); 32 | HttpSession session = request.getSession(); 33 | session.removeAttribute(session.getId()); 34 | if (result.getCode().equals(ResultCause.SUCCESS_CODE)){ 35 | session.setAttribute(session.getId(),userService.getUserInfo(name)); 36 | } 37 | return result; 38 | } 39 | 40 | @RequestMapping(value = "/register", method = {RequestMethod.GET,RequestMethod.POST}) 41 | public @ResponseBody 42 | ResultCause register(UserEntity user){ 43 | return userService.registerUser(user); 44 | } 45 | 46 | @RequestMapping(value = "/test",method = RequestMethod.GET) 47 | public void test() throws IOException { 48 | response.addCookie(new Cookie("nasss","nasss")); 49 | response.getWriter().print(new ResultCause("200","sadfas")); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import cn.nuaa.tomax.entity.ResultCause; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.util.FileCopyUtils; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.multipart.MultipartFile; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.util.List; 14 | 15 | /** 16 | * @Author: ToMax 17 | * @Description: 测试新增的文件上传功能的controller 18 | * @Date: Created in 2018/5/7 15:02 19 | */ 20 | @Controller 21 | @RequestMapping("/upload") 22 | public class FileUploadController { 23 | 24 | /** 25 | * 默认上传文件输出路径 26 | */ 27 | private static final String OUT_DIRECTORY_PATH = "E://tmp/"; 28 | 29 | /** 30 | * 单个文件上传测试,无输入校验(单个文件大小应低于5M) 31 | * @param file 32 | * @return JsonObject 上传结果 33 | * @throws IOException 34 | */ 35 | @RequestMapping(value = "single", method = {RequestMethod.GET,RequestMethod.POST}) 36 | public @ResponseBody 37 | ResultCause uploadSingleFile(MultipartFile file) throws IOException { 38 | FileCopyUtils.copy(file.getBytes(),new File(OUT_DIRECTORY_PATH+file.getOriginalFilename())); 39 | return new ResultCause(ResultCause.SUCCESS_CODE,"文件上传成功"); 40 | } 41 | 42 | 43 | /** 44 | * 多个文件上传测试接口 45 | * @param files 46 | * @return JsonObject 上传结果 47 | * @throws IOException 48 | */ 49 | @RequestMapping(value = "multi", method = {RequestMethod.GET, RequestMethod.POST}) 50 | public @ResponseBody 51 | ResultCause uploadMultiFiles(List files) throws IOException { 52 | for (MultipartFile in : files){ 53 | FileCopyUtils.copy(in.getBytes(),new File(OUT_DIRECTORY_PATH+in.getOriginalFilename())); 54 | } 55 | return new ResultCause(ResultCause.SUCCESS_CODE, "多文件上传成功"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/impl/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service.impl; 2 | 3 | import cn.nuaa.tomax.dao.IHelloDao; 4 | import cn.nuaa.tomax.entity.HelloEntity; 5 | import cn.nuaa.tomax.entity.ResultCause; 6 | import cn.nuaa.tomax.service.IHelloService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.List; 12 | 13 | /** 14 | * @Author: ToMax 15 | * @Description: 16 | * @Date: Created in 2018/5/1 0:04 17 | */ 18 | @Service 19 | public class HelloServiceImpl implements IHelloService{ 20 | 21 | @Resource 22 | private IHelloDao helloDao; 23 | 24 | @Override 25 | public ResultCause addHello(HelloEntity bean) { 26 | ResultCause result = new ResultCause(); 27 | String sql = "insert into hello (name,signature) values (:name,:signature)"; 28 | helloDao.saveHello(sql,bean); 29 | result.setCode(ResultCause.SUCCESS_CODE); 30 | result.setDesc("添加数据成功"); 31 | return result; 32 | } 33 | 34 | @Override 35 | public List listHello() { 36 | String sql = "select * from hello"; 37 | return helloDao.listHello(sql,new Object[]{}); 38 | } 39 | 40 | @Override 41 | public ResultCause updateHelloData(HelloEntity bean) { 42 | ResultCause result = new ResultCause(); 43 | String sql = "update hello set signature = ? where name = ?"; 44 | helloDao.updateHelloData(sql,new Object[]{bean.getSignature(),bean.getName()}); 45 | result.setCode(ResultCause.SUCCESS_CODE); 46 | result.setDesc("更新数据成功"); 47 | return result; 48 | } 49 | 50 | @Override 51 | public ResultCause removeHelloData(String name) { 52 | ResultCause result = new ResultCause(); 53 | String sql = "delete from hello where name = ?"; 54 | helloDao.removeHelloData(sql,new Object[]{name}); 55 | result.setCode(ResultCause.SUCCESS_CODE); 56 | result.setDesc("删除数据成功"); 57 | return result; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /web/login.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/2/20 5 | Time: 11:25 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 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 | 39 | 40 | 41 | 记住密码 42 | 43 | 44 | 45 | 登录 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /web/js/user/login.js: -------------------------------------------------------------------------------- 1 | var username = getCookie('demo_username') 2 | var password = getCookie('demo_password') 3 | var flag = getCookie('demo_flag') 4 | $("#username").val(username!=undefined&&username!=null?username:'') 5 | $("#password").val(username!=undefined&&password!=null?password:'') 6 | if (flag != undefined && flag != null){ 7 | $("#remb").attr('checked','checked') 8 | } 9 | 10 | function go_to_register() { 11 | window.location.href = "register.jsp" 12 | } 13 | 14 | //点击登录按钮效果(登录按钮的id为`loginBtn`) 15 | $("#loginBtn").on('click',function () { 16 | //按照通过input的id获取填写的值 17 | var username = $('#username').val() 18 | var password = $('#password').val() 19 | var param = {'name':username, 'password':password} 20 | post("user/login",param,function (result) { 21 | if (result.code == "200"){ 22 | var flag = $('#remb').is(':checked') 23 | if (flag == true){ 24 | setCookie('demo_username',username) 25 | setCookie('demo_password',password) 26 | setCookie('demo_flag',flag) 27 | }else { 28 | delCookie('demo_username') 29 | delCookie('demo_password') 30 | delCookie('demo_flag') 31 | } 32 | window.location.href = "index.jsp" 33 | }else if (result.code == "400"){ 34 | alert(result.desc) 35 | window.location.href = "login.jsp" 36 | }else { 37 | //TODO:处理其他结果 38 | } 39 | }); 40 | }) 41 | 42 | //设置cookie 43 | function setCookie(name,value) { 44 | var Days = 7 45 | var exp = new Date() 46 | exp.setTime(exp.getTime() + Days*24*60*60*1000) 47 | document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString() 48 | } 49 | // 获取cookie 50 | function getCookie(name) { 51 | var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)"); 52 | if(arr=document.cookie.match(reg)){ 53 | return unescape(arr[2]) 54 | } else{ 55 | return null 56 | } 57 | } 58 | //删除cookies 59 | function delCookie(name) { 60 | var exp = new Date() 61 | exp.setTime(exp.getTime() - 1); 62 | var cval=getCookie(name) 63 | if(cval!=null){ 64 | document.cookie= name + "="+cval+";expires="+exp.toGMTString() 65 | } 66 | } -------------------------------------------------------------------------------- /blogs/README.md: -------------------------------------------------------------------------------- 1 | # 从“零”开始 :Spring MVC 2 | **Author : ToMax** 3 | 4 | > 本学期的设计模式课设要求使用spring之类的Java web框架实现一个B/S架构的应用,一方面,通过该系列博客复习spring mvc的一些知识,另一方面,帮助一些从未接触过web开发的同学能够快速的开始课设。 5 | 6 | ## 简介 7 | 8 | > 系列博客主要构成为开发环境搭建、spring简介、spring之HelloWorld、简单网页开发(想要更好效果的页面开发效果请参考addoneG的相关博客)、数据库开发、登录注册功能的实现、简单留言功能的实现 9 | 10 | ## 目录 11 | 12 | 1. [开发环境搭建](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md) 13 | 2. [建立一个Spring mvc项目,Hello world!](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/Helloworld.md) 14 | 3. [讲一个和Java web项目中mvc有关的情景](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/mvc.md) 15 | 4. [前后端的数据交互](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%89%8D%E5%90%8E%E7%AB%AF%E6%95%B0%E6%8D%AE%E4%BA%A4%E4%BA%92.md) 16 | 5. [增加数据库支持](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%A2%9E%E5%8A%A0%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%AF%E6%8C%81.md) 17 | 6. [登录注册功能的实现](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.md) 18 | 7. [简单留言功能的实现](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E7%AE%80%E5%8D%95%E7%95%99%E8%A8%80%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.md) 19 | 8. [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 20 | 21 | ## 阅读须知 22 | 23 | + 本系列博客的主要目的为快速完成课设的要求,所以会尽量回避一些概念性的东西,为了方便理解,会用一些比较通俗却不一定准确的描述解释一些功能 24 | 25 | + 博客间有一定的连贯性,所以部分解释会在一篇博客之后的博客中给出,所以,见到不是很理解的地方,不需要太关心,继续读下去 26 | 27 | + 会有详细的代码给出,同时会讲解如何在并不熟悉spring的情况下通过一些模仿来实现非复杂功能。所以,大家可以通过系列博客的教程来获取完成课设的手段,但是,具体的功能及实现,需要自己去研究 28 | 29 | + 本系列博客比较适合几乎没有web开发经验的同学、不打算深入学习spring的同学,需要对于java有最起码的了解,熟悉面向对象编程,如果不了解java,在阅读博客前尽量用半天时间完成java基础的学习 30 | 31 | + **提前学习一下java中的一些命名规范,保证编程时所有单词拼写的正确性,避免不必要的错误,这一点很重要** 32 | 33 | + 默认读者对于html、css、javascript有最起码的认识 34 | 35 | + 博客过程中如果发现一些不熟的概念,可以通过百度去了解,但是有可能会出现很多不熟悉的概念,所以尽量根据自身的需要做出取舍,一些概念会在后续的某个地方得到解答,也可能会忽略,但尽量会避免因为概念的理解而影响过程的开发 36 | 37 | + 代码中可能会有很多个人开发的痕迹,切勿抄袭,否则后果自负 38 | 39 | [下一篇:开发环境搭建](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md) 40 | 41 | 42 | 43 | > 如果有帮助的话,来颗star吧 44 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.service.impl; 2 | 3 | import cn.nuaa.tomax.dao.IUserDao; 4 | import cn.nuaa.tomax.entity.ResultCause; 5 | import cn.nuaa.tomax.entity.UserEntity; 6 | import cn.nuaa.tomax.service.IUserService; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.Resource; 10 | import java.sql.Timestamp; 11 | import java.util.List; 12 | 13 | 14 | /** 15 | * @Author: ToMax 16 | * @Description: 17 | * @Date: Created in 2018/5/4 22:48 18 | */ 19 | @Service 20 | public class UserServiceImpl implements IUserService{ 21 | @Resource 22 | private IUserDao userDao; 23 | 24 | @Override 25 | public ResultCause checkUser(String name, String password) { 26 | UserEntity user = getTargetUser(name); 27 | if (user == null){ 28 | //未查到该用户,即用户不存在 29 | return new ResultCause(ResultCause.FAIL_CODE,"用户名或密码错误"); 30 | }else if (user.getPassword().equals(password)){ 31 | //登录验证成功 32 | return new ResultCause(ResultCause.SUCCESS_CODE,"登录成功"); 33 | } 34 | //密码错误 35 | return new ResultCause(ResultCause.FAIL_CODE,"用户名或密码错误"); 36 | } 37 | 38 | @Override 39 | public ResultCause registerUser(UserEntity user) { 40 | if (getTargetUser(user.getName()) != null){ 41 | return new ResultCause(ResultCause.FAIL_CODE,"用户名已存在"); 42 | }else { 43 | //设置注册时间 44 | user.setTime(new Timestamp(System.currentTimeMillis())); 45 | //id为自增字段,所以不需要在这里设置 46 | String sql = "insert into user (name,password,time) values (:name,:password,:time)"; 47 | userDao.saveUser(sql,user); 48 | } 49 | return new ResultCause(ResultCause.SUCCESS_CODE,"注册成功"); 50 | } 51 | 52 | @Override 53 | public UserEntity getUserInfo(String name) { 54 | String sql = "select name,id from user where name = ?"; 55 | return userDao.listUsers(sql,new Object[]{name}).get(0); 56 | } 57 | 58 | /** 59 | * 根据用户名查找用户,因为本系统用户名唯一,所以用户名查找到的结果为单个用户对象 60 | * 同时,因为在登录验证和注册查重中均有查询用户对象的需求,所以将这部分代码拿出, 61 | * 进行复用 62 | * @param name 63 | * @return 如果查询结果非空,返回唯一的结果,否则返回空值 64 | */ 65 | private UserEntity getTargetUser(String name){ 66 | String sql = "select * from user where name = ?"; 67 | List userEntities = userDao.listUsers(sql,new Object[]{name}); 68 | return (userEntities!=null&&userEntities.size()>0)?userEntities.get(0):null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /web/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="cn.nuaa.tomax.entity.UserEntity" %><%-- 2 | Created by IntelliJ IDEA. 3 | User: VULCAN 4 | Date: 2018/4/20 5 | Time: 22:16 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | 12 | 13 | 14 | 留言板 15 | 16 | 57 | 58 | <% 59 | UserEntity user = (UserEntity) session.getAttribute(session.getId()); 60 | String username = "未登录"; 61 | Integer userId = -1; 62 | if (user != null){ 63 | username = user.getName(); 64 | userId = user.getId(); 65 | } 66 | %> 67 | 68 | 69 | 70 | 71 | 留言板 72 | 73 | Username 74 | 75 | Logout 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 提交 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/dao/DaoHelper.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.dao; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.jdbc.core.BeanPropertyRowMapper; 5 | import org.springframework.jdbc.core.JdbcTemplate; 6 | import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; 7 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Author: ToMax 15 | * @Description: 16 | * @Date: Created in 2018/4/30 16:09 17 | */ 18 | @Repository 19 | public class DaoHelper { 20 | 21 | @Autowired 22 | private JdbcTemplate jdbcTemplate; 23 | public JdbcTemplate getJdbcTemplate() { 24 | return jdbcTemplate; 25 | } 26 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { 27 | this.jdbcTemplate = jdbcTemplate; 28 | } 29 | @Autowired 30 | private NamedParameterJdbcTemplate namedParameterJdbcTemplate; 31 | public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { 32 | return namedParameterJdbcTemplate; 33 | } 34 | 35 | public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) { 36 | this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; 37 | } 38 | 39 | //查询 40 | public List query(String sql, Class cls){ 41 | return this.jdbcTemplate.query(sql,new BeanPropertyRowMapper(cls)); 42 | } 43 | 44 | public List query(String sql,Object[] params,Class cls){ 45 | return this.jdbcTemplate.query(sql,params,new BeanPropertyRowMapper(cls)); 46 | } 47 | 48 | public List query(String sql){ 49 | return this.jdbcTemplate.queryForList(sql); 50 | } 51 | //使用命名sql查询 52 | public List query(String sql, Map maps, Class clazz){ 53 | List l = this.namedParameterJdbcTemplate.query(sql,maps,new BeanPropertyRowMapper(clazz)); 54 | return l; 55 | } 56 | 57 | //查询返回值为基础对象类型 58 | public Object query(String sql,Object id,Class clazz){ 59 | return this.jdbcTemplate.queryForObject(sql,new Object[]{id},clazz); 60 | } 61 | 62 | //更新 63 | public boolean execSql(String sql){ 64 | if(sql==null || sql.equals("")){ 65 | return false; 66 | } 67 | jdbcTemplate.execute(sql); 68 | return true; 69 | } 70 | public boolean update(String sql,Object[] params){ 71 | if(sql==null || sql.equals("")){ 72 | return false; 73 | } 74 | jdbcTemplate.update(sql,params); 75 | return true; 76 | } 77 | //插入对象 78 | public boolean insertByBean(String sql,Object bean){ 79 | if(sql==null || sql.equals("")){ 80 | return false; 81 | } 82 | BeanPropertySqlParameterSource ps = new BeanPropertySqlParameterSource(bean); 83 | namedParameterJdbcTemplate.update(sql,ps); 84 | return true; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /blogs/mvc.md: -------------------------------------------------------------------------------- 1 | # 讲一个和Java web项目中mvc有关的情景 2 | **Author : ToMax** 3 | 4 | 5 | ## **一大段文字来袭 ... ...** 6 | 7 | > 在开始正式去实现一些功能模块之前,为了让后面的东西不那么难以理解,所以简单谈一谈一个不那么有意思的情景,大多内容源于本人这一年的断断续续的java web开发和学习经验,或许会有一些帮助,如果实在觉得无聊,快速浏览一遍也未尝不可。 8 | 9 | 现在有一家非常不错的饭店,索性叫他做Spring饭店吧(不必将这家饭店与Spring框架关联,其实关系不大)。 10 | 11 | 作为一名食客,ToMax来到了Spring饭店用餐,刚进门,就被饭店的简约风格所吸引。 12 | 13 | 环顾四周,ToMax选中了一个靠近窗口的位置坐下,服务员紧随而至,不过即便服务员不过来,ToMax也准备叫一个服务员过来,因为确实是很饿了。 14 | 15 | 在从服务员的手中接过菜单后,ToMax快速地点了几道爱吃的菜,同时希望服务员能够快一点,还没开口,肚子就开始叫了起来。 16 | 17 | 服务员接过菜单,娴熟地将菜单拿到了饭店管理订单的地方。不知道该怎么描述这个地方,总之,是一个发布号令的地方,似乎每个楼层都有一个,通知相应的厨师该做哪些菜了。显然,Spring饭店是一家规格不小的饭店,有许多位大厨在工作。 18 | 19 | 与厨房外面相比,厨房里就不那么安静了,几乎所有的厨师都在紧张的工作着,认真地处理每一道菜,当然不是一道一道菜地去做,厨师们会时不时地切换操作的锅,也会腾出手来去做一些其他的工作,总之,会在同时产出好几道菜,不过似乎是分工明确,spring饭店的大师傅每个人只负责相应的菜品。 20 | 21 | 作为大师傅,当然不是需要完成菜品烹饪的所有步骤的,比如说配菜这种工作,自然会有助手在一旁完成,大师傅们更多的是对配好的菜进行加工处理。 22 | 23 | 当然,也有一些大师傅是擅长切菜、摆盘的,总之,整个厨房里,各司其职,井然有序,高效率地完成着菜品。 24 | 25 | 所以,很快,ToMax点的菜就完成了,由厨房小师傅从厨房递出,又回到了那个发号施令的地方,服务员查看了订单,将菜品快速地端到了ToMax的桌上。 26 | 27 | 其实,ToMax是非常幸运的,因为这时的食客还不算太多,用餐最高峰期,即便厨房效率再高,还是会多等一些时间,并且有时,ToMax爱吃的菜可能会因为材料耗完而做不了,不过这种情况下,敬业的服务员会及时地通知ToMax,然后更换点的菜。 28 | 29 | 看着桌上的菜,还等什么,当然是开吃了...... 30 | 31 | (这段码于0:13,真的很饿) 32 | 33 | 熟悉计算机的同学,或许会从中获得一些共鸣。那么这样的一个情景和web项目又有什么关系呢? 34 | 35 | 回想上一篇博客中,有在`src`目录下的`cn.nuaa.tomax`包下建立了许多目录,它们是`controller`目录、`service`目录、`dao`目录、`entity`目录,没有说明他们的作用,下面,将会在上述的情景中,找到他们各自比较合适的切入点。 36 | 37 | 众所周知,`MVC`是`model`、`view`、`controller` 38 | 39 | 对于用户而言,所能直接接触到的往往只有`view`,先入为主意味着想要应用更受欢迎,设计并实现一些风格一致、大方美观的`view`是非常重要的,这和一家精致的饭店是一样的,有一个清新的门面、雅致的环境,极大地提高了用餐体验。 40 | 41 | 用户与客户端之间的交互,有些是直接由客户端处理了,但还有很多需要从客户端发出请求,向服务端请求数据。而服务员是串联食客与饭店服务的中介,服务员将食客的就餐请求传递到相应业务范围的管理中心。 42 | 43 | 到了后端,对于不同业务会由不同`controller`处理,当然,`controller`本身不具备提供请求中需求数据的能力,不过没关系,作为控制器,它只需要将请求的内容交到相应的业务层去处理,并将处理的结果准确地返回给前端就可以了。上述地管理中心也是类似,将食客点的菜交给相应的厨师去完成,并将厨师完成的菜让服务员在端给客户。 44 | 45 | `service`就是业务层了,比如说用户业务、订单业务等等,一个`service`中会集中处理一堆业务下的功能,比如在用户业务中可以包括用户的信息管理、登录、注册。在饭店中,与之类似的就是大厨们的工作了,一个大厨负责一个菜系。 46 | 47 | `service`中可以做很多数据处理,但是前提是有数据,所以,会在`service`中使用许多的`dao`。`Data access object`,数据访问对象,几乎就是在`java`应用层去获取数据需要写的最底层的代码了,再向下便是框架封装的接口、JDBC、数据库了。`dao`通常对应的是对一张表的操作,也就是说,每建一张表,就会有一个`dao`,`dao`中会写一些对于相应表的增删查改操作。正如厨师很少去配菜,配菜由一些助手完成,而这些负责不同配菜工作的员工就和`dao`比较类似了。 48 | 49 | 在这里又得捎带提到`entity`,实体类,源于数据库,每一张表都有维护一些关系,表字段组织起来就可以抽象出一个类。一张表,就可以映射出一个实体类,表字段与实体类属性一一对应,在`java`中,实体类基本是这种形式的,拥有源于数据库表字段的私有化成员变量,并且为每一个成员变量都提供一组`get`、`set`方法作为访问接口。所以,对于表中的每一条记录都可以产生一个相应实体类的对象。联想一下,`entity`是不是就可以与配菜类比了。 50 | 51 | 顺带一提,`entity`与`dao`属于`model`。 52 | 53 | 回到`service`,有了数据,业务层就极具表现力了,可以应用各种各样的操作和算法使数据符合请求中需要的那样然后返回。大厨在有了配好的菜之后也可以尽情的展示烹饪技巧。 54 | 55 | 顺带提一下,在饭店中,厨师以及配菜的员工都是可以被替代的,当离职一名厨师,还可以找到具有相同能力的厨师,虽然他们的处理的方式未必相同,但是最终可以完成食客需要的那一道菜品。同理,对于`dao`和`service`,通常希望它们也是可以替代的,所以通常将`dao`和`service`做成`interface`,然后会用相应接口的实现类来表述具体的`dao`和`service`,具体会在后面展开。 56 | 57 | 到这里,是不是对于即将开展的具体功能的开发要做些什么有一个大体的认识了呢。 58 | 59 | [下一篇:前后端的数据交互](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%89%8D%E5%90%8E%E7%AB%AF%E6%95%B0%E6%8D%AE%E4%BA%A4%E4%BA%92.md) 60 | 61 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 62 | 63 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 64 | 65 | ## **小结** 66 | 67 | 写了这些更多是想要再次将自己对于java web开发的印象去梳理一遍,以上纯属拙见,不过这里用来完成课设应该是足够了。 68 | 69 | 70 | 71 | > 如果有帮助的话,来颗star吧 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/controller/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.controller; 2 | 3 | import cn.nuaa.tomax.entity.FormEntity; 4 | import cn.nuaa.tomax.entity.GoodEntity; 5 | import cn.nuaa.tomax.entity.ResultCause; 6 | import com.sun.org.apache.regexp.internal.RE; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.ModelMap; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @Author: ToMax 18 | * @Description: 19 | * @Date: Created in 2018/4/5 23:34 20 | */ 21 | @Controller 22 | @RequestMapping("/") 23 | public class HelloWorldController { 24 | @RequestMapping(value = "/hello" ,method = RequestMethod.GET) 25 | public String sayHello() { 26 | return "index"; 27 | } 28 | 29 | @RequestMapping(value = "/getGoodList",method = RequestMethod.GET) 30 | public @ResponseBody List getGoodList(){ 31 | List goodEntities = new ArrayList<>(); 32 | goodEntities.add(new GoodEntity(1,"iphone",5000)); 33 | goodEntities.add(new GoodEntity(2,"ipad",4000)); 34 | goodEntities.add(new GoodEntity(3,"macpro",120000)); 35 | return goodEntities; 36 | } 37 | 38 | @RequestMapping(value = "/checkToken", method = RequestMethod.GET) 39 | public @ResponseBody 40 | ResultCause checkToken(String token){ 41 | if (token.equals("1")){ 42 | return new ResultCause(ResultCause.SUCCESS_CODE,"验证成功"); 43 | }else { 44 | return new ResultCause(ResultCause.FAIL_CODE,"验证失败"); 45 | } 46 | } 47 | 48 | // /** 49 | // * 表单输入值依次映射到参数上 50 | // * @param name 51 | // * @param signature 52 | // * @return 53 | // */ 54 | // @RequestMapping(value = "/form",method = {RequestMethod.GET,RequestMethod.POST}) 55 | // public @ResponseBody 56 | // ResultCause testForm(String name, String signature){ 57 | // System.out.println(name+"'s is : "+signature); 58 | // return new ResultCause("200",name+"'s is : "+signature); 59 | // } 60 | 61 | /** 62 | * 表单输入映射到对象上 63 | * @param form 64 | * @return 65 | */ 66 | @RequestMapping(value = "/form",method = {RequestMethod.GET,RequestMethod.POST}) 67 | public @ResponseBody 68 | ResultCause testForm(FormEntity form){ 69 | System.out.println(form.getName()+"'s is : "+form.getSignature()); 70 | return new ResultCause("200",form.getName()+"'s is : "+form.getSignature()); 71 | } 72 | 73 | @RequestMapping(value = "ajax_test", method = {RequestMethod.GET,RequestMethod.POST}) 74 | public @ResponseBody 75 | ResultCause testAjax(FormEntity form){ 76 | System.out.println(form.getName()+"'s is : "+form.getSignature()); 77 | return new ResultCause("200",form.getName()+"'s is : "+form.getSignature()); 78 | } 79 | 80 | @RequestMapping(value = "get_list", method = {RequestMethod.GET,RequestMethod.POST}) 81 | public @ResponseBody 82 | List getList(){ 83 | List resultCauses = new ArrayList<>(); 84 | resultCauses.add(new ResultCause("200","汤茂行")); 85 | resultCauses.add(new ResultCause("300","Java")); 86 | resultCauses.add(new ResultCause("400","Hello World")); 87 | return resultCauses; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/cn/nuaa/tomax/configuration/WebConfig.java: -------------------------------------------------------------------------------- 1 | package cn.nuaa.tomax.configuration; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.databind.module.SimpleModule; 5 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.http.converter.HttpMessageConverter; 10 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 11 | import org.springframework.web.multipart.commons.CommonsMultipartResolver; 12 | import org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter; 13 | import org.springframework.web.servlet.ViewResolver; 14 | import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 15 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 16 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 17 | import org.springframework.web.servlet.view.InternalResourceViewResolver; 18 | 19 | import java.text.SimpleDateFormat; 20 | import java.util.List; 21 | 22 | /** 23 | * @Author: ToMax 24 | * @Description: spring mvc java configuration 25 | * @Date: Created in 2018/4/18 21:30 26 | */ 27 | @Configuration 28 | @EnableWebMvc 29 | @ComponentScan("cn.nuaa.tomax") 30 | public class WebConfig extends WebMvcConfigurerAdapter{ 31 | /** 32 | * @Description 配置视图解析器 33 | * @return 34 | */ 35 | @Bean 36 | public ViewResolver viewResolver(){ 37 | InternalResourceViewResolver resolver = new InternalResourceViewResolver(); 38 | resolver.setPrefix(""); 39 | resolver.setSuffix(".jsp"); 40 | resolver.setExposeContextBeansAsAttributes(true); 41 | return resolver; 42 | } 43 | 44 | /** 45 | * @Description 配置静态资源的处理 46 | * @param configurer 47 | */ 48 | @Override 49 | public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 50 | configurer.enable(); 51 | } 52 | 53 | /** 54 | * 支持response转换为json数据 55 | * @param converters 56 | */ 57 | @Override 58 | public void extendMessageConverters(List> converters) { 59 | MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); 60 | ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper(); 61 | 62 | objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); 63 | 64 | SimpleModule simpleModule = new SimpleModule(); 65 | simpleModule.addSerializer(Long.class, ToStringSerializer.instance); 66 | simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); 67 | objectMapper.registerModule(simpleModule); 68 | 69 | jackson2HttpMessageConverter.setObjectMapper(objectMapper); 70 | //放到第一个 71 | converters.add(0, jackson2HttpMessageConverter); 72 | } 73 | 74 | // /** 75 | // * 配置multipart resolver,用于文件上传处理 76 | // * 单个上传文件大小应不超过5M 77 | // * @return 78 | // */ 79 | // @Bean(name = "multipartResolver") 80 | // public CommonsMultipartResolver getCommonsMultipartResolver(){ 81 | // CommonsMultipartResolver resolver = new CommonsMultipartResolver(); 82 | // resolver.setMaxUploadSizePerFile(5242880); 83 | // return resolver; 84 | // } 85 | } 86 | -------------------------------------------------------------------------------- /blogs/开发环境搭建.md: -------------------------------------------------------------------------------- 1 | # 开发环境搭建 2 | **Author : ToMax** 3 | 4 | > 基于Spring MVC进行web开发,在spring框架本身的引入之前,需要进行java 开发环境的配置以及相关工具的准备。包括JDK、Tomcat、MySQL、Intellij IDEA。下面,简要的介绍相关的配置。 5 | 6 | ## 一、JDK的安装与环境配置 7 | 8 | > JDK 是java开发工具包,包括java基础的库和JVM等 9 | 10 | [下载地址](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 11 | 12 |  13 | 14 | 选中accept license agreement ,并选择与自己操作系统相符合的版本下载 15 | 16 | JDK 下载完成后,直接默认安装即可 17 | 18 | **不需要配置环境变量,安装好就可以用**,所以这里不谈如何配置jdk环境变量,如果想体验在命令中编译java程序的话,自行百度java环境变量配置,在本系列博客中,不配置环境变量也不会有影响 19 | 20 | ## 二、Tomcat的下载 21 | 22 | > Tomcat是Web容器,将基于java开发的web应用部署在Tomcat中后,便可以从客户端进行访问 23 | 24 | [下载地址](https://tomcat.apache.org/download-80.cgi) 25 | 26 |  27 | 28 | 只需要下载一个与系统兼容的压缩包版的即可,下载完成后,找一个合适的地方解压,记住解压的目录,在下一篇博客中会提到其具体的使用,**同样,解压完成后也不需要额外的操作,不需要启动或者配置其他的东西** 29 | 30 | ## 三、MySQL的下载与安装 31 | 32 | > Mysql是一款常用的关系型数据库管理系统,具有轻量级、开源等优点。有兴趣的同学可以自行下载,配置相关的环境,这里,我将平时一直在用的版本放到了网盘中,觉得配置环境比较麻烦的话,可以直接从网盘中下载,有启动脚本,所以不用专门去做一些配置。 33 | 34 | 35 | [网盘地址 提取密码: rxp2](https://pan.baidu.com/s/1BhweqMus4A9mTWy4Sd-h9A) 36 | 37 |  38 | 39 | 其中有两个压缩包,一个是`mysql`,一个是`sqlyog`,其中`sqlyog`是一款数据库工具,可以提供一个UI,这样就不用在终端中操作数据库了。 40 | 41 | 首先解压`mysql` 42 | 43 | 在`mysql`目录下,依次右击`registeService.bat`、`startService.bat`并以管理员身份运行。 44 | 45 | 解压`sqlyog` 46 | 47 | 首先用`SQLyog-11.2.4-0.x86.exe`安装,安装完成后,点击`SQLyog-11.2.4-0.x86.reg`注册 48 | 49 | 之后可以在桌面的快捷方式中打开`sqlyog` 50 | 51 | 打开后首先是连接界面,如果如下图已经有一个默认连接的话,则直接选择连接,否则点击新建,创建一个名为`localhost`的连接,其主机地址为`localhost`,用户名为`root`,密码为空(如何修改用户名密码这里就不提了,可以自行尝试),端口为`3306` 52 | 53 |  54 | 55 | 连接后进入应用 56 | 57 |  58 | 59 | 、 60 | 61 | 关于数据库的配置暂时就介绍到这,相关的使用会在后续的博客中涉及,有打算在课设中进行数据库开发的同学可以先行通过菜鸟教程简单地了解下`sql`语句的基本语法,并在`sqlyog`中尝试一下。 62 | 63 | [菜鸟教程](http://www.runoob.com/sql/sql-tutorial.html) 64 | 65 | 初步了解下数据库的增删查改操作即可 66 | 67 | ## 四、Intellij IDEA的下载与安装 68 | 69 | > Intellij IDEA,java语言集成开发环境,JetBrains的产品,目前应该是属于Java最优雅的一款IDE了,UI好像使用java开发的,大写的服 70 | 71 | [下载地址](https://www.jetbrains.com/idea/download/#section=windows) 72 | 73 |  74 | 75 | 下载Ultimate版本的,不过该版本是试用版的,试用期后需要付费,关于激活稍后再提 76 | 77 | 下载完成后,运行安装,处理安装地址以外,其他均默认安装即可,其中只有一个流程是要选择是否作为.java文件的默认打开方式,是否建立桌面快捷方式,这里按照个人喜好来。 78 | 79 | 安装成功之后,打开IDEA,初始化,下面列出一些关键步骤的截图 80 | 81 |  82 | 83 |  84 | 85 | > 关于激活,大致有这几种情况,第一种是上网搜索IDEA 激活码或者注册码,在下面这个界面填写;第二种是在IDEA官网注册一个学生账号,可以免费使用JetBrains的产品;第三种就是下载破解补丁;第四种就是暂时试用,等到过期后就会失去专业版的特性。目前虽然大部分被封了,但是有从搜索到的词条一条一条试下去的话,应该还是找得到的。如果只是短期使用,试用也是一个选择。 86 | 87 | 这里,暂时提供一个激活方式,即在`License server`选项的`server address`中输入`http://btsha.com:41017`,如果不可用,请自行选择激活或者注册学生账号的方式 88 | 89 |  90 | 91 | 激活成功后,会有一些IDEA相关的初始化配置,可以选择Skip跳过这些,直接默认配置,也可以根据喜好去做一些选择,**建议选了自己喜欢的黑色主题或白色主题后,直接Skip**,如果自己向后选择的话,只有vim一项是不建议安装的。 92 | 93 |  94 | 95 | 下图这一步的都是默认安装的,尽量别选`Disable` 96 | 97 |  98 | 99 | 上一步结束后的这一步都是默认不安装的,可以都不用装,如果要装,千万别装vim,除非对于vim很熟 100 | 101 | ![这里图片忘记截了]() 102 | 103 | 之后就可以打开IDEA的进入界面了 104 | 105 |  106 | 107 | 选择Create New Project, 写一个java的Hello world程序,选择第一项:`java` 建立一个单纯的java项目 108 | 109 |  110 | 111 | 初次进入需要在IDEA中配置java环境,即点击上述图片红框圈中的New,选择jdk的安装目录,默认安装是在`C://Program Files/java/`目录下 112 | 113 |  114 | 115 | 选择完后,不需要点其他的一些选项,直接点击最下方的`Next`选项 116 | 117 |  118 | 119 | 在这里,可以选择内置的模板,不过下面的展示是不选择模板,直接选择`Next`选项 120 | 121 |  122 | 123 | 选择项目路径 124 | 125 | ![这里的图片忘记截了]() 126 | 127 | 初次进入,会有如下显示,直接去掉 128 | 129 |  130 | 131 | 大体的视图,目前只需要关心src目录,将在该目录中写一个HelloWorld程序 132 | 133 |  134 | 135 | 在src目录上右键->new->Java Class,或者Alt+insert->Java Class,命名为`HelloWorld`,并添加如下代码 136 | 137 | ``` Java 138 | public static void main(String [] args){ 139 | System.out.println("Hello , Intellij IDEA"); 140 | } 141 | ``` 142 | 143 | 添加完后有如下视图 144 | 145 |  146 | 147 | 在添加了`main`函数后,`HelloWorld`类区域出现了两个绿色倒三角标,随便点击一个运行即可(其他运行方式,当光标在`HelloWorld`区域时,快捷键ctrl+shift+f10为运行当前类的`main`函数,当然还有一些方式,这里不再扩展,可以自行研究) 148 | 149 | 运行之后,如图 150 | 151 |  152 | 153 | 发现在项目目录中多出了一个`out`目录,该目录是输出目录,即项目编译后按照配置的一些输出。 154 | 155 | **至此,Java开发环境配置完成** 156 | 157 | ## 小结 158 | 159 | 本篇描述了整个过程所需的基础配置,包括java开发环境的配置,其中tomcat、mysql的具体使用会在后续博客中出现。 160 | 161 | 有兴趣的话,不妨了解一些IDEA的常用快捷键,作为一款出色的IDE,IDEA具有相当完善的快捷键系统,不夸张的说,只掌握其中常用的一部分,大致就可以告别鼠标了 162 | 163 | [下一篇:建立一个Spring mvc项目,Hello world!](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/Helloworld.md) 164 | 165 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 166 | 167 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 168 | 169 | 170 | 171 | > 如果有帮助的话,来颗star吧 -------------------------------------------------------------------------------- /blogs/前后端数据交互.md: -------------------------------------------------------------------------------- 1 | # 前后端的数据交互 2 | **Author : ToMax** 3 | 4 | > 在整个系统中,存在客户与客户端之间的交互(这部分主要属于前端开发,不会太多的涉及)、前端与后端之间的交互、后端业务与数据库之间的交互。这一篇博客将讨论一些前后端之间的数据交互。在之前的`HelloWorld`那篇博客的HelloWorld部分,有介绍过后端响应前端请求后返回请求数据的内容,所以,这里会介绍前端如何传送一些请求数据到后端。 5 | 6 | ## GET 方法 7 | 8 | 在`HelloWorld`的Hello world实例中,有提到过在浏览器的地址栏中输入形如`localhost:8080/checkToken?token=1`的url,这就是一种GET请求。 9 | 10 | 当然,在交互中通常不会使用这种方法。不过,可以使用这种方法来简单地代替单元测试。在开发过程中,对于一些功能模块,在完成后,需要设计一些单元测试进行验证,即使有强大的框架支持,一些非常累的,所以,在功能接口不那么复杂、没有维护需求的情况下,为了节省一些时间,可以简单地使用GET请求的方式进行测试。 11 | 12 | ## 表单提交(使用post方法) 13 | 14 | 表单提交是一种非常常见的形式,如注册表单、登录表单等等,可以很方便地将数据提交到后台,下面,简单地谈一个表单提交的例子。 15 | 16 | + 在`web`目录下新建一个`form.jsp`,并添加如下代码 17 | 18 | ``` html 19 | 20 | 21 | 表单提交 22 | 23 | 24 | 25 | 姓名 26 | 签名 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | 这是一个非常简单的表单,`form`标签中有两个属性,`action`属性代表表单提交的地址,这里是相对地址,如果是在地址栏中输的话应该为`localhost:8080/form`,`method`属性代表请求的方法,这里选择了`post`方法。表单中包括两个输入框和一个提交按钮,对于姓名输入框,加了一个`name`属性,属性的值为`name`,签名的`name`属性值为`signature` 34 | 35 | + 下面写相应的相应相应请求的方法,在`HelloWorldController`中新增如下方法 36 | 37 | ``` java 38 | @RequestMapping(value = "/form",method = RequestMethod.POST) 39 | public @ResponseBody 40 | ResultCause testForm(String name, String signature){ 41 | System.out.println(name+"'s is : "+signature); 42 | return new ResultCause("200",name+"'s is : "+signature); 43 | } 44 | ``` 45 | 46 | 该方法的请求方法设为了POST方法,同时方法中有两个参数,`name`和`signature`参数,对应于表单中两个输入框的`name`属性值,在请求的过程中,框架会将请求参数取出,并通过名称进行映射。 47 | 48 | 在方法中的执行一条打印操作,并返回一个result。 49 | 50 | + 启动服务器,并打开form.jsp 51 | 52 | 两种方法打开`jsp`文件,一种是直接在地址栏中输入`localhost:8080/form.jsp`,另一种是在IDEA中的`form.jsp`的代码编辑区会有一个浮动的选框,显示了一组浏览器的icon,选择一个电脑中有的浏览器打开该`jsp`(建议是`chrome`,如果没看见浮窗就多动动鼠标就会出现) 53 | 54 | + 进入`form.jsp`后,在表单中输入相应的内容,提交 55 | 56 |  57 | 58 | + 提交后,浏览器打印返回值 59 | 60 |  61 | 62 | + 同时,在IDEA的控制台中也会有相应的数据打印 63 | 64 | ![图略]() 65 | 66 | 这样,表单的交互就算完成了,不过,通常表单提交后会跳转到另一个界面,即相应表单请求的方法应该是个代表相应页面名称的字符串,或者在js中对于表单的返回值进行处理,不过因为这部分不是要提到的重点,所以不再展开。 67 | 68 | 注意,这时候直接在地址栏中输入`localhost:8080/form?name=tomax&signature=hhh`是没用的,因为没有设置该方法可以处理GET请求,所以,要想测试该方法,需要将`@RequestMapping`的`method`参数值改为`method = {RequestMethod.GET,RequestMethod.POST}`,重启服务器后就可以访问了(看`@RequestMapping`的源码就可以发现,`method`参数是支持数组的)。 69 | 70 | **再看另一种请求参数的映射形式** 71 | 72 | 在上述的操作中,将表单的输入框组的值依次映射到相应方法的同名参数上,但是考虑到假设表单中的输入框组数量过多,全部以参数形式作为方法的变量便显得有些冗余了。设想一个场景,用户信息修改,用户通过表单提交个人信息进行个人信息修改,那么其实个人信息的集合其实是用户类的一个对象,很自然的就会有将这些数据映射到对象上的想法。 73 | 74 | + `form.jsp`,在`entity`包下添加一个`FormEntity`的java类,代码如下 75 | 76 | ``` java 77 | public class FormEntity { 78 | 79 | private String name; 80 | private String signature; 81 | 82 | public String getName() { 83 | return name; 84 | } 85 | 86 | public void setName(String name) { 87 | this.name = name; 88 | } 89 | 90 | public String getSignature() { 91 | return signature; 92 | } 93 | 94 | public void setSignature(String signature) { 95 | this.signature = signature; 96 | } 97 | } 98 | ``` 99 | 100 | + 同时修改`HelloWorldController`的`testForm`方法如下 101 | 102 | ``` java 103 | 104 | @RequestMapping(value = "/form",method = {RequestMethod.GET,RequestMethod.POST}) 105 | public @ResponseBody 106 | ResultCause testForm(FormEntity form){ 107 | System.out.println(form.getName()+"'s is : "+form.getSignature()); 108 | return new ResultCause("200",form.getName()+"'s is : "+form.getSignature()); 109 | } 110 | 111 | ``` 112 | 113 | + 重启服务器,并访问`form.jsp`,输入值后提交表单,发现结果相同 114 | 115 | 这里,同样是用`name`,将表单输入框组中的值依次映射到`FormEntity`的`form`对象的同名成员变量上去(相应的成员变量必须有`get`,`set`方法)。 116 | 117 | 假如没有框架的话,想要将请求参数装配到一个对象中以供后续操作,需要从`request`中依次用参数的`name`去将相应的`value`取出,这样将会产生大量的代码,而框架则将这部分的操作封装了起来,为开发节省了许多开销。 118 | 119 | 关于表单提交的讨论仅到此为止。 120 | 121 | ## ajax(使用post方法) 122 | 123 | > `ajax`,异步JavaScript和XML,是一种可以用于在不重新加载整个页面的情况下,和服务器交换数据并更新部分网页的技术 124 | 125 | 这里,因为本人几乎没有写过前端,唯一还算熟悉的js框架就只有`jquery`一款了,所以下面的内容中基于的js框架便是`jquery`(仅作演示,前端的开发,可以选择自己比较喜欢的方式)。 126 | 127 | + 首先要进行准备工作 128 | 129 | 从Github的本项目中的web目录下拷贝`css`、`fonts`、`js`几个目录到自己的`web`目录下,里面包含了`jquery`、`bootstrap`以及其他的一些依赖。(也可以自己去下载相应的依赖,凭个人喜好创建web的目录结构) 130 | 131 | + 在web目录下新建`ajax.jsp`,并添加如下代码 132 | 133 | ``` html 134 | 135 | 136 | ajax 137 | 138 | 139 | 发送ajax 请求 140 | 141 | 142 | 143 | 144 | 145 | ``` 146 | + 在`web`目录下的js目录中,新建`ajax_test`目录,并在`ajax_test`目录下新建`ajax_test.js`,并添加如下代码 147 | 148 | ``` javascript 149 | $("#send-ajax").on('click',function () { 150 | var param = {'name':'ToMax','signature':'hhh'} 151 | post('ajax_test',param,function (data) { 152 | alert(data.desc) 153 | }) 154 | }); 155 | ``` 156 | 这段代码其实是一个函数,表示监听上述`ajax.jsp`中的`button`的点击事件。在事件中定义了一个param变量,是一个对象,具有`name`和`signature`两个成员,分别有一个对应的`value`,下面就要将这部分的值传递到后台,调用了一个post函数(定义在`ajaxfunc.js`中),可以`ctrl+点击`查看该函数如下 157 | 158 | ``` javascript 159 | function post(url,param,callback){ 160 | $.ajax({ 161 | url : url, 162 | type : 'post', 163 | data : param, 164 | dataType : 'json', 165 | timeout : 100000, 166 | success : function(data) { 167 | callback(data); 168 | }, 169 | error : function(e) { 170 | console.log("ERROR: ", e); 171 | }, 172 | done : function(e) { 173 | console.log("DONE"); 174 | enableSearchButton(true); 175 | }, 176 | complete : function() { 177 | } 178 | }); 179 | } 180 | ``` 181 | 182 | 该函数需要三个参数,第一个是请求的地址,和`form`表单的`action`类似,第二个是请求参数,即`param`变量,第三个是回调函数,即请求响应成功后执行的函数,在上述的js中,该回调函数会在原界面上弹出弹窗并打印返回的结果。可以看见这里的`ajax`中采用了`post`方法,并且数据格式为`json`,成功了会执行回调函数。 183 | 184 | + 下面需要完成相应的响应方法,在`HelloWorldController`中添加如下方法 185 | 186 | ``` java 187 | @RequestMapping(value = "ajax_test", method = {RequestMethod.GET,RequestMethod.POST}) 188 | public @ResponseBody 189 | ResultCause testAjax(FormEntity form){ 190 | System.out.println(form.getName()+"'s is : "+form.getSignature()); 191 | return new ResultCause("200",form.getName()+"'s is : "+form.getSignature()); 192 | } 193 | ``` 194 | 195 | + 重启服务器,访问`ajax.jsp`,并点击按钮,有如下结果 196 | 197 |  198 | 199 | 发现,成功的输出了`testAjax`返回值`ResultCause`的`desc`变量的值。为此,可以将绑定到回调函数中的`data`变量等同于在响应方法中定义的返回值,并可以灵活地使用其成员变量。 200 | 201 | **或许到这里,还不足以看出这种交互所能完成的形式,下面再做进一步的尝试** 202 | 203 | + 在`ajax.jsp`中添加如下代码 204 | ``` html 205 | 显示列表 206 | 207 | ``` 208 | 209 | + 在`ajax_test.js`中添加监听事件 210 | 211 | ``` javascript 212 | $("#display-list").on('click',function () { 213 | post('get_list',[],function (data) { 214 | liHtml = "" 215 | for (var i = 0; i" 217 | liHtml += "code : "+data[i].code 218 | liHtml += ", desc : "+data[i].desc 219 | liHtml += "" 220 | } 221 | $("#list").html(liHtml) 222 | }) 223 | }); 224 | ``` 225 | 226 | 这段代码的作用是向后端请求一个列表数据,并将该数据显示到页面中去 227 | 228 | + 在`HelloWorldController`中添加新的响应方法 229 | 230 | ``` java 231 | @RequestMapping(value = "get_list", method = {RequestMethod.GET,RequestMethod.POST}) 232 | public @ResponseBody 233 | List getList(){ 234 | List resultCauses = new ArrayList<>(); 235 | resultCauses.add(new ResultCause("200","ToMax")); 236 | resultCauses.add(new ResultCause("300","Java")); 237 | resultCauses.add(new ResultCause("400","Hello World")); 238 | return resultCauses; 239 | } 240 | ``` 241 | 其中,返回值变为了一个`list` 242 | 243 | + 重启服务器,访问`ajax.jsp`并点击获取列表的按钮,有如下结果 244 | 245 |  246 | 247 | 成功获取了list,并以列表形式在原界面显示了出来。 248 | 249 | 至此,关于前后端数据交互的讨论便告一段落。 250 | 251 | ## 小结 252 | 253 | 这一篇中,主要谈了几种前后端数据交互的形式,过程中尽可能地回避讨论前端的知识,一方面这不是本系列博客中关注的重点,另一方面是因为本人对于前端开发能力不足。 254 | 255 | `ajax`的这种形式看起来是最为灵活的,所以,在后续的操作中,会主要采用这种形式进行交互。 256 | 257 | 258 | 259 | [下一篇:增加数据库支持](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E5%A2%9E%E5%8A%A0%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%AF%E6%8C%81.md) 260 | 261 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 262 | 263 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 264 | 265 | > 如果有帮助的话,来颗star吧 266 | -------------------------------------------------------------------------------- /blogs/增加数据库支持.md: -------------------------------------------------------------------------------- 1 | # 增加数据库支持 2 | 3 | **Author : ToMax** 4 | 5 | > 上一篇中实现了前后端之间的交互,这一篇将会增加与数据库之间的交互。在应用中,产生大部分的数据必然不会停留在程序中,而是需要进行持久化,而数据库便是持久化最常用的一种操作。这里,将会运用关系型数据库`MySql` 6 | 7 | ## 必要的环境准备 8 | 9 | 其实基本上的工作都在之前的博客中完成了,仅有为数不多的事情需要在接下来完成 10 | 11 | + 新建一个数据库 12 | 13 | 打开`sqlyog`,或者其他类似的软件,连接到`localhost`,新建一个数据库,名字按照自己的需要去定义,这里,暂且命名为`design_pattern`,注意,在新建的时候,应选择`UTF-8`字符集,这样就允许在数据库中保存中文字符了,如图 14 | 15 |  16 | 17 | + 在`design_pattern`中新建一张表名为`hello`,有如下字段(name,signature) 18 | 19 |  20 | 21 | + 调整相应的数据库配置 22 | 23 | 打开`cn.nuaa.tomax.configuration`中的`AppConfig`,找到`dataSource`方法中的`ds.setUrl`那一行,其中的值应为`jdbc:mysql://localhost:3306/design_pattern?useUnicode=true&characterEncoding=utf-8&useSSL=true`,这里暂时需要关心的就是`localhost:3306/design_pattern`这一段,代表的是数据库的地址,`/`前是数据库服务的地址,可以是远端,也可以是本地,后面的是数据库名称。所以,需要将数据库名称调整为该项目要使用的数据库名称。 24 | 25 | + 添加模板的工具类,简化开发 26 | 27 | 从Github本项目的`cn.nuaa.tomax.dao`目录下复制`DaoHelper`类进入自己的项目的同级`dao`目录下。其中在`JdbcTemplate`基础上做了简单的封装,使得数据库的增删查改方法可以简化一些。 28 | 29 | ## 开始测试数据库的连接 30 | 31 | + 为`hello`表写一个`HelloEntity` 32 | 33 | 在`cn.nuaa.tomax.entity`包下新建一个`HelloEntity`,然后它的成员变量应与`hello`表一一对应,有如下的命名规则 34 | 35 | **对于数据库的表名为xxx_xxx(x均为小写字母,多个单词时,不同单词间用‘_’相连)的形式,其映射的实体类名应为XxxXxxEntity(x与之前一一对应,不同单词的首写字母均为大写)** 36 | 37 | **对于表中的字段,命名方式与表名命名方式相同,也是类似于xxx_xxx(name,user_name等等)的形式,映射到实体类中的字段时,为xxxXxx,第一个单词的首字母小写,其他单词的首字母大写** 38 | 39 | **每个映射出来的成员变量xxxXxx需要有get set 方法,getXxxXxx , setXxxXxx(在代码编辑区用右键+generate+getter and setter可以快速生成每个成员变量的getset方法)** 40 | 41 | **对于每个字段到成员变量的数据类型基本维持不变,varchar->String等等** 42 | 43 | 所以`HelloEntity`中的代码如下 44 | 45 | ``` java 46 | private String name; 47 | private String signature; 48 | public HelloEntity(){} 49 | public HelloEntity(String name, String signature) { 50 | this.name = name; 51 | this.signature = signature; 52 | } 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public void setName(String name) { 58 | this.name = name; 59 | } 60 | 61 | public String getSignature() { 62 | return signature; 63 | } 64 | 65 | public void setSignature(String signature) { 66 | this.signature = signature; 67 | } 68 | ``` 69 | 70 | + 为`hello`表写一个`dao` 71 | 72 | 在`cn.nuaa.tomax.dao`目录下新建一个`java interface`(新建java类时在name的下面有一个kind可以选择,选择interface就可以,或者在建完java class后将class修改为interface也可以),名为`IHelloDao`(命名的意思为hello表的dao interface,之后的命名类似) 73 | 74 | 为什么是`interface`? 75 | 76 | 还记得在前面的一篇中讲到负责烧某一列菜的厨师可以变更,即操作的过程可变,但是完成的工作不会变得那个例子吗?这里,采用接口得形式定义每一个`dao`,并在之后用一个具体得实现类去实现它,就可以达成相应得目的。实现一定程度上的解耦。 77 | 78 | 在其中写一些抽象方法。 79 | 80 | ``` java 81 | public interface IHelloDao { 82 | /** 83 | * 保存单个HelloEntity对象 84 | * @param sql 保存sql语句 85 | * @param bean HelloEntity对象 86 | */ 87 | public void saveHello(String sql, HelloEntity bean); 88 | 89 | /** 90 | * 查询满足一定条件的hello列表 91 | * @param sql 查询sql语句 92 | * @param keys 查询中需要用的约束值数组 93 | * @return 94 | */ 95 | public List listHello(String sql, Object[] keys); 96 | 97 | /** 98 | * 更新满足一定条件的hello数据 99 | * @param sql 100 | * @param keys 101 | */ 102 | public void updateHelloData(String sql, Object[] keys); 103 | 104 | /** 105 | * 删除满足一定条件的hello数据 106 | * @param sql 107 | * @param keys 108 | */ 109 | public void removeHelloData(String sql, Object[] keys); 110 | } 111 | 112 | ``` 113 | 114 | 为最基本的增删查改四种方法。其中`Object[] keys`为`Object`数组,其中的每一个`Object`可以是任意数据类型的数据。 115 | 116 | + 为`IHelloDao`写相应的实现类 117 | 118 | 在`dao`目录下新建一个`package`,命名为`impl`,在`impl`包下新建一个java类,命名为`HelloDaoImpl`(很容易看出命名规则),其中代码如下 119 | 120 | ``` java 121 | 122 | @Repository 123 | public class HelloDaoImpl extends DaoHelper implements IHelloDao { 124 | @Override 125 | public void saveHello(String sql, HelloEntity bean) { 126 | this.insertByBean(sql,bean); 127 | } 128 | 129 | @Override 130 | public List listHello(String sql, Object[] keys) { 131 | return this.query(sql,keys,HelloEntity.class); 132 | } 133 | 134 | @Override 135 | public void updateHelloData(String sql, Object[] keys) { 136 | this.update(sql,keys); 137 | } 138 | 139 | @Override 140 | public void removeHelloData(String sql, Object[] keys) { 141 | this.update(sql,keys); 142 | } 143 | } 144 | 145 | ``` 146 | 147 | 下面分析一下其中写的内容,首先在类上方有一个类注解,名为`@Repository`,这个注解标注该类是一个`dao`用于进行数据库访问。同时在项目启动的时候,会自动扫描具有该注解的类,放入容器中。 148 | 149 | 该类继承自`DaoHelper`,可以调用`DaoHelper`中的方法。同时实现`IHelloDao`接口。 150 | 151 | 接着实现`IHelloDao`中定义的抽象方法。 152 | 153 | 第一个方法,`saveHello`,其中的实现是调用`DaoHelper`中的`insertByBean`方法,只需要传入插入的`sql`语句以及相应需要插入的对象即可实现。 154 | 155 | 第二个方法,`listHello`,其中的实现是调用`DaoHelper`中的`query`方法,只需要传入查询`sql`语句、查询的限定值`keys`为`Object`数组、以及查询结果将映射到某一种实体类上。(查询的结果并不是直接就是一个与表相对应的实体类的对象list,而是框架中的一些方法会通过实体类的类结构将查询结果依次映射到实体类的对象上,最终返回一个相应实体类的list,而获取实体类的类结构的方法就是用相应的实体类的.class,这个地方过于抽象,不再展开谈,有兴趣的同学可以研究下java的Class类,没有兴趣就不建议花这个时间了) 156 | 157 | 第三个、第四个方法其实是类似的,因为删除其实就是更新操作,不过这里分开增加印象,其中就是调用了`update`方法,传入删除或者更新的`sql`语句以及相应的限定值`keys`。 158 | 159 | 当然,随着应用背景以及实现功能的变化,可能会有更多更复杂的操作要去使用,更强大的方法去调用,但目前而言,这四个方法已经可以实现很多东西了。 160 | 161 | + 写一个`hello`业务 162 | 163 | 在`cn.nuaa.tomax.service`中新建一个名为`IHelloService`的`java interface` 164 | 165 | 有如下代码 166 | 167 | ``` java 168 | public interface IHelloService { 169 | /** 170 | * 增加hello数据 171 | * @param bean 172 | * @return 173 | */ 174 | public ResultCause addHello(HelloEntity bean); 175 | 176 | /** 177 | * 获取hello数据 178 | * @return 179 | */ 180 | public List listHello(); 181 | 182 | /** 183 | * 更新hello数据,更新对应name的signature 184 | * @param bean 185 | * @return 186 | */ 187 | 188 | public ResultCause updateHelloData(HelloEntity bean); 189 | 190 | /** 191 | * 删除指定name的hello数据 192 | * @param name 193 | * @return 194 | */ 195 | public ResultCause removeHelloData(String name); 196 | } 197 | 198 | ``` 199 | 200 | 业务也是比较简单,提供了对数据直接增删查改的功能 201 | 202 | + 下面写`IHelloService`的实现类 203 | 204 | 在`cn.nuaa.tomax.service`下新建一个`impl`package,在包下新建一个java类,名为`HelloServiceImpl`,代码如下 205 | 206 | ``` java 207 | @Service 208 | public class HelloServiceImpl implements IHelloService{ 209 | 210 | @Resource 211 | private IHelloDao helloDao; 212 | 213 | @Override 214 | public ResultCause addHello(HelloEntity bean) { 215 | ResultCause result = new ResultCause(); 216 | String sql = "insert into hello (name,signature) values (:name,:signature)"; 217 | helloDao.saveHello(sql,bean); 218 | result.setCode(ResultCause.SUCCESS_CODE); 219 | result.setDesc("添加数据成功"); 220 | return result; 221 | } 222 | 223 | @Override 224 | public List listHello() { 225 | String sql = "select * from hello"; 226 | return helloDao.listHello(sql,new Object[]{}); 227 | } 228 | 229 | @Override 230 | public ResultCause updateHelloData(HelloEntity bean) { 231 | ResultCause result = new ResultCause(); 232 | String sql = "update hello set signature = ? where name = ?"; 233 | helloDao.updateHelloData(sql,new Object[]{bean.getSignature(),bean.getName()}); 234 | result.setCode(ResultCause.SUCCESS_CODE); 235 | result.setDesc("更新数据成功"); 236 | return result; 237 | } 238 | 239 | @Override 240 | public ResultCause removeHelloData(String name) { 241 | ResultCause result = new ResultCause(); 242 | String sql = "delete from hello where name = ?"; 243 | helloDao.removeHelloData(sql,new Object[]{name}); 244 | result.setCode(ResultCause.SUCCESS_CODE); 245 | result.setDesc("删除数据成功"); 246 | return result; 247 | } 248 | } 249 | ``` 250 | 251 | 下面同样简要介绍一下其中的实现。 252 | 253 | 首先,类注解`@Service`表示该类是一个`service`,为业务层。 254 | 255 | 该类实现了`IHelloService`接口。 256 | 257 | 有一个类型了`IHelloDao`,名为`helloDao`的成员变量。其上使用`@Resource`进行注解,通过该注解标注后,就不需要在编码阶段来`new`这个`IHelloDao`的对象(接口的对象为其实现类的对象,正常操作需要`IHelloDao helloDao = new HelloDaoImpl();`),框架会从容器中自动去找到一个符合条件的对象注入到`helloDao`中。这样就可以调用封装在`helloDao`中的`hello`表的操作方法。 258 | 259 | 第一个方法,返回值为`ResultCause`,这里写的是`result`中的状态码始终为`200`,这样其实是不合理的,应该会根据数据库操作的结果,以及业务过程中的状态得出一个状态码。不过这里暂且简写。增加`hello`数据的`sql`语句很简单 260 | 261 | `insert into` --> 插入到 262 | `hello` --> `hello` 表 263 | `(name,signature)` --> `hello`表的`name`、`signature`字段(千万不要拼写错误) 264 | `values` --> 值为 265 | `(:name,:signature)` --> 这里因为是插入一个对象,所以代表将对象中名为`name`的成员变量的值赋给前面`hello`表目标字段集合中对应位置上的那一个,即`:name`->`name`,`:signature`->`signature`,`:`表示为对象的成员变量。(一定记住,后面的为成员变量的名称,前面的为字段的名称,可以不一样) 266 | 267 | 接着调用`helloDao`的插入方法,将一个`hello`对象插入即完成 268 | 269 | 第二个方法,返回值为`hello`列表,简介一下该`sql`语句 270 | `select` --> 从...选取 271 | `*` --> 相应表的全部字段,也可以取部分字段,形式为`name,signature ` 272 | `from` --> 从 273 | `hello` --> `hello` 表 274 | 这里是直接查表中的全部记录,如果想要差部分记录,需要用`where`去限定,所以在执行`helloDao`相应方法时传来一个空的`Object`数组 275 | 276 | 第三个方法,返回值为`ResultCause`,同为简写,没有判断错误。执行了更新语句。 277 | `update`|`hello`|`set`|`signature = ?`|`where`|`name = ?`|简单断了一下句,很容易理解,`?`为通配符,表示之后需要在这里填上相应的值。相应的值写在了`Object`数组中,顺序应和`?`在`sql`语句中的顺序一致。 278 | 279 | 第四个方法,返回值同上。执行删除语句,原理类似。`delete from`|`hello`|`where`|`name=?` 280 | 281 | 至此,该业务基本完成,下面需要在`controller`中调用具体业务 282 | 283 | + 完成`controller`中的方法(暴露给客户端) 284 | 285 | 不妨在`cn.nuaa.tomax.controller`中再建一个名为`HelloController`的java类,并添加如下代码 286 | 287 | ``` java 288 | @Controller 289 | @RequestMapping("/hello") 290 | public class HelloController { 291 | @Resource 292 | private IHelloService helloService; 293 | @RequestMapping(value = "/addHello", method = RequestMethod.GET) 294 | public @ResponseBody 295 | ResultCause addHelloData(HelloEntity hello){ 296 | return helloService.addHello(hello); 297 | } 298 | @RequestMapping(value = "/getHelloList", method = RequestMethod.GET) 299 | public @ResponseBody 300 | List getHelloList(){ 301 | return helloService.listHello(); 302 | } 303 | @RequestMapping(value = "/updateHello", method = RequestMethod.GET) 304 | public @ResponseBody 305 | ResultCause updateHello(HelloEntity hello){ 306 | return helloService.updateHelloData(hello); 307 | } 308 | @RequestMapping(value = "/deleteHello", method = RequestMethod.GET) 309 | public @ResponseBody 310 | ResultCause deleteHelloData(String name){ 311 | return helloService.removeHelloData(name); 312 | } 313 | } 314 | ``` 315 | 316 | 简单介绍一下。 317 | 318 | 首先是类注解`@Controller`表示该类为一个`controller`,其次是类注解`@RequestMapping("/hello")`,表示该类方法的访问地址为`localhost:8080/hello`(只考虑本地的情况) 319 | 320 | 一个类型为`IHelloService`名为`helloService`的成员变量,使用`@Resource`进行注解。用于访问`helloService`中的业务,在这个项目中,启动时,会将`HelloServiceImpl`的对象注入到`helloService`中。 321 | 322 | 接下来的几个方法有之前博客的介绍,这里就不再过多的交代了。所有的方法都是用`GET`方法的目的是方便测试,这里并不是为了完成真正的功能,而只是测试一下数据库的支持。 323 | 324 | + 启动服务器 325 | 326 | 首先访问`localhost:8080/hello/addHello?name=tomax&signature=hhh`(值随便填) 327 | 328 |  329 | 330 | 前往`sqlyog`的`course_design`数据库的`hello`表,查看是否添加了相应的记录,没有的话记得刷新一下看一看 331 | 332 |  333 | 334 | 可以多添加几条记录 335 | 336 | 然后访问`localhost:8080/hello/getHelloList` 337 | 338 |  339 | 340 | 访问`localhost:8080/hello/updateHello?name=tomax&signature=hhhh`之后查看数据库相应字段是否发生更新 341 | 342 | 访问`localhost:8080/hello/deleteHello?name=tomax`之后查看数据库相应记录是否删除 343 | 344 | 如果全部都没有问题,那么很好,该项目已经具备了数据库开发的基础了。 345 | 346 | ## 小结 347 | 348 | 本篇介绍了引入数据库支持,并实现了比较简单的数据库操作,完成了一个相对完整的访问流程。下一篇博客就会开始实现一些具体的功能。 349 | 350 | 在开始下一篇之前,有兴趣可以先尝试增加一个测试,按照`name`查询`hello`数据 351 | 352 | 这里,再提一下在博客中出现的`@Controller`、`@Service`、`@Repository`注解。 353 | 354 | 事实上,这三个注解虽然名字不同,但功能完全相同,不妨看一下它们的源码,一模一样的定义,除了名字,但是就是这些不同的名字,使得可以较为规范地区别不同地业务层级。它们共同的作用就是告诉容器有这么个玩意存在,可以用他们所注解的类作为资源注入到需要的地方(例如`@Resource`注解的地方)简单介绍这么些。 355 | 356 | [下一篇:登录注册功能的实现](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.md) 357 | 358 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 359 | 360 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 361 | 362 | 363 | 364 | > 如果有帮助的话,来颗star吧 -------------------------------------------------------------------------------- /blogs/Helloworld.md: -------------------------------------------------------------------------------- 1 | # 建立一个Spring mvc项目,Hello world! 2 | **Author : ToMax** 3 | > 在这篇博客中,将完整的呈现如何建立一个Spring mvc应用,包括项目的建立、一些额外的依赖的引入以及Hello world 4 | 5 | ## 建立一个Spring 项目 6 | 7 | #### 第一步,Create new project,选择左侧的Spring项,并勾选Spring MVC、Web Application、 8 | 9 |  10 |  11 | 12 | #### 第二步,选择Next,进入项目保存路径界面,填写项目名称 13 | 14 | + 点击Finish后,IDE会帮助去下载相应的依赖,下载完成后就可以打开项目 15 | 16 |  17 | 18 | + 项目打开后界面 19 | 20 |  21 | 22 | + 项目目录 23 | 24 | 多了`web`目录,里面会写一些`web`的代码,以及放`web`配置 25 | 26 | 27 | #### 第三步,配置Tomcat 28 | >记得,上一篇中,下载完tomcat后,只是做了解压处理,这里,在IDEA中配置tomcat容器 29 | 30 | + 选择程序启动项的Edit Configurations 31 | 32 |  33 | 34 | + 选择添加一种运行方案,这里选择tomcat的容器 35 | 36 |  37 | 38 | + 配置添加一个tomcat容器 39 | 40 |  41 | 42 |  43 | 44 | + 选择Tomcat的解压路径(该目录下包含bin、conf等目录) 45 | 46 |  47 | 48 |  49 | 50 | + 选择OK 51 | 52 |  53 | 54 | + 点击Fix处理一个问题 55 | 56 |  57 | 58 | + 点击Fix 后,问题会自动解决,进入下面的界面 59 | 60 |  61 | 62 | + 切回server tab页 63 | 64 |  65 | 66 | #### 第四步,处理一些项目依赖问题 67 | 68 | + 点击Project structure 69 | 70 |  71 | 72 | + Fix 73 | 74 |  75 | 76 | + 点击OK返回 77 | 78 | #### 第五步,启动 79 | 80 | + 点击绿色倒三角标启动,稍等片刻,弹出浏览器显示一下信息则启动成功 81 | 82 |  83 | 84 | + 还不是很明显,所以,我们来修改web目录下的index.jsp 85 | 86 |  87 | 88 | + 因为只是更改了网页部分,没有需要重新编译的java项,所以只需要选择update即可,操作如图 89 | 90 |  91 | 92 | + 更新后回到浏览器F5刷新后如图,发现index已更新,所以由idea默认生成的index.jsp即为默认访问的页面 93 | 94 |  95 | 96 | + 这里,不妨再啰嗦下,在web目录下新建一个login.jsp,并填写相应的内容,详细见图 97 | 98 |  99 |  100 | 101 | + 点击运行项,update 一下,刷新浏览器,并将地址栏修改为localhost:8080/login.jsp,如图 102 | 103 |  104 | 105 | + 下面尝试将默认启动的网页改为index.jsp,首先,找到WEB-INF目录下的web.xml 106 | 107 |  108 | 109 | + 在工作区添加以下代码 110 | 111 | ``` xml 112 | 113 | login.jsp 114 | 115 | ``` 116 |  117 | 118 | + 点击run,重启服务器(Restart server)[快捷键为shift+f10] 119 | 120 |  121 | 122 | + 发现默认路径已经改为了login.jsp,好了,现在切回正题 123 | 124 | #### 第六步,增加spring的配置与依赖 125 | 126 | + 这里我将采用基于java配置spring,而不是使用传统的xml文件进行配置,以减轻额外学习xml的成本 127 | 128 | + 首先,暂时删除WEB-INF目录下的applicationContext.xml、dispatcher-servlet.xml,同时将web.xml中web-app标签内除了刚刚增加的welcome-file-list标签以外的内容,删除多余的内容的目的是防止与之后基于java的配置产生冲突 129 | 130 |  131 | 132 | + 然后在lib目录里添加servlet、jackson、dbcp、mysql-connector-java的依赖,这四个依赖在github本项目中的同级lib目录下可以获取,直接拷贝即可 133 | 134 |  135 | 136 | + 对于jar包,需要分别add as library,**每个目录下**(千万别所有目录一起添加了,每个目录下的内容都是一个整体)全部选中集中添加一次即可 137 | 138 |  139 | 140 | + 添加后如图 141 | 142 |  143 | 144 | + 然后需要点开Project structure, Fix problems,均为add to artifact 145 | 146 |  147 | 148 | + 之后,我们需要创建java的开发目录,在src目录下添加如下包(右键或者alt+insert呼出菜单栏) 149 | 150 |  151 | 152 |  153 | 154 | + 右键建好的包,选择show in explorer 进入对应的文件夹 155 | 156 |  157 |  158 | 159 | + 进入tomax目录,建立如下图所示几个文件夹,其中configuration是配置java的文件夹,res是资源目录,utils是工具目录,其他的目录意义将在下一篇博客中进行详细的解释,res和utils目录并非必须,也可以根据喜好来命名 160 | 161 |  162 | 163 | + 下面要在configuration目录下添加spring框架的配置java文件,为了降低难度,直接从github本项目相应的目录下复制四个java文件进入即可,当作默认配置好的就好,后面用到时会做具体的解释(可能复制时会因为不同人对应包名的命名不同,所以可能需要调整包名,但正常情况下idea会帮助我们自动调整) 164 | 165 |  166 | 167 | 复制完成后,还要对其中的一些信息作调整 168 | 169 | 首先是`WebConfig`,其中有一个类注解为`@ComponentScan("cn.nuaa.tomax")`,需要将`cn.nuaa.tomax`修改为自己同级包的名称 170 | 171 | 接着是`RootConfig`,将其中的`@CompoentScan`的`backPackages`中的`cn.nuaa.tomax`改为自己的包名 172 | 173 | 最后是`AppConfig`,将`@ComponentScan`的`cn.nuaa.tomax`的值修改为自己的包名 174 | 175 | + 至此,配置内容算是添加完成了 176 | 177 | #### 第七步,Hello world 178 | 179 | + 首先,需要在cn.nuaa.tomax.controller包下添加一个HelloWorldController. 180 | 181 |  182 | 183 | + 打开HelloWorldController ,添加如下代码 184 | 185 | ``` java 186 | @Controller 187 | @RequestMapping("/") 188 | public class HelloWorldController { 189 | @RequestMapping(value = "/hello" ,method = RequestMethod.GET) 190 | public String sayHello() { 191 | return "index"; 192 | } 193 | } 194 | ``` 195 | 这里,简单解释下这个controller的作用 196 | 197 | 自上而下看,第一个出现的是一个叫做`@Controller`的东西,在java中,这种形式叫做注解,用来做代码级别的说明,简单理解就是一种元数据,通过这些元数据,程序可以获取一些代码相关的信息,运用反射技术(反射在这里不再扩展,不然又会引入更多的概念,有机会会补充在以后的博客中,有兴趣的同学可以去了解下,不过反射本身存在一定的理解难度,不准备深入掌握java开发的同学可以忽视它),可以让程序解读注解信息,从而使程序具有一定主动执行的能力,而不是完全被动地处理程序员的编码。 198 | 199 | 回归正题,`@Controller`注解的作用即标注这个类的角色是一个controller,熟悉MVC的同学对此一定不会陌生。 200 | 201 | 这个controller的访问地址靠`@RequestMapping`来注解,它的参数为`"/"`,对应服务器访问的根目录,即`localhost:8080/`,那么可以确定,假设这里填的是``@RequestMapping("/path")``,那么对应的访问路径即为`localhost:8080/path`。 202 | 203 | 继续看类中定义的`sayHello()`方法,同样使用了`@RequestMapping`注解申明。`sayHello()`的``RequestMapping``注解中有两个参数,`"/hello"`表示该方法的访问地址,即`localhost:8080/hello`,假设该类的访问地址为`localhost:8080/path`的话,`sayhello()`的访问地址就变成了,`localhost:8080/path/hello`,同时第二个参数为``RequestMethod.GET``(关于http的请求方法,自行百度,主要用到的有GET方法和POST方法),即该方法将会处理的是以GET方法访问`localhost:8080/hello`的请求。 204 | 205 | 现在,大致清楚了该方法的作用,即处理以GET方法访问`localhost:8080/hello`的请求,下面说明它是如何处理的 206 | 207 | 在`sayHello()`方法中只写了`return "index";`,它的意义是会通过在config配置好的`resolver`(已经作为默认配置在之前提供,对应config/WebConfig中的viewReslover)将`index`这个字符串映射到一个具体的`view`(MVC中view的概念)中(按照已经作的配置,会映射到web目录下的index.jsp上),即访问`localhost:8080/hello`会访问`index.jsp` 208 | 209 | 那么,我们重启一下服务器(即运行中的restart server 选项),重启成功后,在地址栏输入`localhost:8080/hello`,将会发现,网页从默认的`login.jsp`跳转到了`index.jsp` 210 | 211 |  212 | 213 | 在上述的`sayHello()`方法中,只是单纯的通过字符串返回了一个jsp,而没有进行任何的附加值,但是实际的应用中,我们需要为这个请求添加一些在服务端产生的数据,而这种操作往往是通过`model`(MVC中model的概念)在`view`中加以呈现,在java中有一种非常简单的方法实现这种目的,即通过在`sayHello()`(即处理当前请求的方法中)增加参数`ModelMap model`为`sayHello(ModelMap model)`来给请求增加一个model,在处理请求的过程中,根据需要为model通过`addAttribute()`方法来增加一些值(model 是一个map,key是字符串,value是一个对象),而jsp提供了一些标签,可以通过这些标签直接访问请求中附加的model的一些值并显示在网页中。 214 | 215 | 不过,这里不会详细提jsp的一些特色标签,而是基本不会使用html中不包含的标签进行开发以降低学习成本,下面,将展示如何反馈一些信息以相应客户端的请求 216 | 217 | 对于一个正常的请求,我们通常会做出两种处理,第一种是这个请求请求的是某种服务端的数据或者资源,例如用户信息、商品信息,或者是想要下载一个文件;第二种是向服务端输送一些数据,如用户的注册,商品的上架等等,当然也可能是校验一些数据,如登录、校验验证码之类的这里也归为第二种。 218 | 219 | 那么对于以上提到的第一种情况,服务端做的响应应返回相应的数据,如用户列表、商品列表;对于第二种情况,服务端相应返回状态码,成功状态、失败状态或者其他预定义的一些状态。那么客户端在拿到这些相应的数据之后,就可以做相应的处理。 220 | 221 | **先谈第一种,返回请求的数据** 222 | 223 | 假定一个情景,我们需要返回一个商品列表的数据 224 | 225 | 在`cn.nuaa.tomax.entity`目录下添加一个java类`GoodEntity`(在entity包上右键new或者alt+insert 选择java class),命名为`GoodEntity`,添加如下代码 226 | 227 | ``` Java 228 | package cn.nuaa.tomax.entity; 229 | 230 | /** 231 | * @Author: ToMax 232 | * @Description: 233 | * @Date: Created in 2018/4/24 0:10 234 | */ 235 | public class GoodEntity { 236 | private long id; 237 | private String name; 238 | private float price; 239 | 240 | public GoodEntity() {} 241 | 242 | public GoodEntity(long id, String name, float price) { 243 | this.id = id; 244 | this.name = name; 245 | this.price = price; 246 | } 247 | 248 | public long getId() { 249 | return id; 250 | } 251 | 252 | public void setId(long id) { 253 | this.id = id; 254 | } 255 | 256 | public String getName() { 257 | return name; 258 | } 259 | 260 | public void setName(String name) { 261 | this.name = name; 262 | } 263 | 264 | public float getPrice() { 265 | return price; 266 | } 267 | 268 | public void setPrice(float price) { 269 | this.price = price; 270 | } 271 | } 272 | ``` 273 | 274 | 这是一个POJO(plain old java object)即只有私有化成员变量并且为每一个成员变量定义一组get,set方法,具有严格的命名规范,本身的意义是抽象了一个商品类。 275 | 276 | 下面我们需要通过请求获取一个商品列表数据,在`cn.nuaa.tomax.controller.HelloWorldController`中添加一个新的方法,暂且命名为`getGoodsList()`,同时给它一个访问路径为`/getGoodList` 277 | 278 | ``` Java 279 | @RequestMapping(value = "/getGoodList",method = RequestMethod.GET) 280 | public @ResponseBody List getGoodList(){ 281 | List goodEntities = new ArrayList<>(); 282 | goodEntities.add(new GoodEntity(1,"iphone",5000)); 283 | goodEntities.add(new GoodEntity(2,"ipad",4000)); 284 | goodEntities.add(new GoodEntity(3,"macpro",120000)); 285 | return goodEntities; 286 | } 287 | ``` 288 | 289 | 可以发现,这里方法的返回值不再是一个`String`,而是一个商品类的list,不难理解,因为想要获取的数据就是一个商品列表信息,但是为了和之前讲的将返回值映射到一个view上去做区别,这里在该方法的返回值上增加了一个`@ResponseBody`注解,通过该注解,加上在`WebConfig`中的配置(配置已添加,直接当成默认配置来用就好),系统会将返回值处理成一个`JSONArray`返回到前台以供相应的处理,同样,为了方便直接去访问这个接口,仍然将该方法申明为GET请求访问。 290 | 291 | 重启服务器,在浏览器地址栏中输入`localhost:8080/getGoodList`,结果如下 292 | 293 |  294 | 295 | **再谈第二种** 296 | 297 | 其实原理上是一样的,只不过需要实现定义一个抽象返回值的类来返回处理结果,所以,同样在`cn.nuaa.tomax.entity`中添加一个java类:`ResultCause`,类的内容如下 298 | 299 | ``` Java 300 | package cn.nuaa.tomax.entity; 301 | 302 | /** 303 | * @Author: ToMax 304 | * @Description: 305 | * @Date: Created in 2018/4/24 23:43 306 | */ 307 | public class ResultCause { 308 | 309 | public static final String SUCCESS_CODE = "200"; 310 | public static final String FAIL_CODE = "400"; 311 | 312 | private String code; 313 | private String desc; 314 | 315 | public ResultCause() {} 316 | 317 | public ResultCause(String code, String desc) { 318 | this.code = code; 319 | this.desc = desc; 320 | } 321 | 322 | public String getCode() { 323 | return code; 324 | } 325 | 326 | public void setCode(String code) { 327 | this.code = code; 328 | } 329 | 330 | public String getDesc() { 331 | return desc; 332 | } 333 | 334 | public void setDesc(String desc) { 335 | this.desc = desc; 336 | } 337 | } 338 | 339 | ``` 340 | 341 | 该类仅包含了两个成员,code(状态码),desc(状态描述),以及两个字符串常量,一个`SUCCESS_CODE`,`FAIL_CODE`,分别表示成功与失败两种状态,当然也会有其他的状态,不过目前这两种已经够用了,当需要时可以再行扩展。如果是需要加以规范,或许会在设计时便确定专门的由常量构成的类来管理肯能出现的code和desc,这里简化这方面的处理,desc会直接在需要的时候赋值。 342 | 343 | 下面模拟一个验证身份的请求,通过前端传来一个token,如果token为1的话,验证成功,否则,验证失败,为了实现这个功能,在`cn.nuaa.tomax.controller`中添加一个新的方法`checkToken()`,其访问地址为`localhost:8080/checkToken` 344 | 345 | ``` Java 346 | 347 | @RequestMapping(value = "/checkToken", method = RequestMethod.GET) 348 | public @ResponseBody 349 | ResultCause checkToken(String token){ 350 | // 这里的1因为是只会用在这一个地方,所以没有专门设置一个状态来描述 351 | if (token.equals("1")){ 352 | return new ResultCause(ResultCause.SUCCESS_CODE,"验证成功"); 353 | }else { 354 | return new ResultCause(ResultCause.FAIL_CODE,"验证失败"); 355 | } 356 | } 357 | 358 | ``` 359 | 360 | 在这个新添加的方法中,返回了`ResultCause`这个类的对象,同时多了一个参数`token`,在方法中对于`token`做了具体的判断,然后返回预定义的状态即相应的描述。显然`token`的值是由请求的参数而来的,在GET方法做的请求中,可以通过在请求的URL后用?name=value的形式来增加参数,这里即`localhost:8080/checkToken?token=1`或者token后跟上其他的数字 361 | 362 | 重启服务器,在浏览器地址栏一次输入`localhost:8080/checkToken?token=1`,`localhost:8080/checkToken?token=2`,结果如下 363 | 364 |  365 | 366 |  367 | 368 | 结果如设定的是一样的。 369 | 370 | 至此,Hello world算是完成了 371 | 372 | ## 小结 373 | 374 | 这一篇博客讲述了如何建立一个spring的项目,并且完成HelloWorld程序,部分地方讲得会比较冗余,主要是为了加深从未使用过IDEA或者类似IDE得同学对于开发环境得印象,部分地方会显得有些说不清楚,是因为对于一个成熟的应用框架而言,即便很小的切入点都会牵扯出大量的知识点,而知识点本身又会衍生出一些知识点,所以很难通过几篇博客将这些知识梳理清楚,像梳理清楚的话,那就不停的google或者百度吧,需要有一定的耐心,当然,即便不那么懂也是没关系的,继续进行下去,在多个例子中,总会有很多的收获。 375 | 376 | 在HelloWorld中,只是提到了很简单的几个方法,但其实这些比较简单的形式足以支撑许多功能的controller开发了,其实,有想像力的同学已经可以使用这些形式做出许多很有用的表达,在下一篇博客中,将会通过一些情景来描述web开发 377 | 378 | [下一篇:讲一个和Java web项目中mvc有关的情景](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/mvc.md) 379 | 380 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 381 | 382 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 383 | 384 | 385 | 386 | > 如果有帮助的话,来颗star吧 -------------------------------------------------------------------------------- /blogs/登录注册功能的实现.md: -------------------------------------------------------------------------------- 1 | # 登录注册功能的实现 2 | 3 | **Author : ToMax** 4 | 5 | > 在本篇博客中,将具体的讨论如何完成登录注册功能。 6 | 7 | ## 首先,分析一波需求,确定将要实现哪些功能 8 | 9 | > 考虑到部分同学没有开发经验,所以,这里简化部分注册登录的功能 10 | 11 | ### 注册 12 | 13 | + 用户名、密码登录系统 14 | 15 | + 登录状态记录 16 | 17 | + 记住密码 18 | 19 | + 登录注销 20 | 21 | ## 数据库设计 22 | 23 | > 确定了需求之后,需要建相应的表,这里涉及到的仅有用户功能,所以只需要建立`user`表(真实过程中,需要考虑整体的需求,不能只关注这一个功能去建表,这里简化) 24 | 25 | ``` sql 26 | 表名 : user 27 | 字段如下 : 28 | 字段名 数据类型 长度 是否主键 是否自增 备注 29 | id int Y Y 用户的id,唯一主键 30 | name varchar 64 N N 用户名 31 | password varchar 32 N N 密码 32 | time datetime N N 注册时间 33 | ... ... ... ... ... 34 | 这里仅列出必须的几个字段(时间非必须,可结合自身需要预留一些字段,如性别、年龄、手机号、邮箱、登录次数、用户状态等等,以备功能扩展) 35 | ``` 36 | 37 | 建表截图如下: 38 | 39 |  40 | 41 | 或者有如下建表语句 42 | ```sql 43 | CREATE TABLE `user` ( 44 | `id` int(11) NOT NULL AUTO_INCREMENT, 45 | `name` varchar(64) DEFAULT NULL, 46 | `password` varchar(32) DEFAULT NULL, 47 | `time` datetime DEFAULT NULL, 48 | PRIMARY KEY (`id`) 49 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 50 | ``` 51 | 52 | 建完表后有两种思路(对于一个人而言),一种是先完成后端的功能接口,一种是先实现前端页面。这里我是先实现后端的一些基本的接口,然后完成界面并实现对接,最终再实现一些额外的功能。 53 | 54 | ## 实现后端的接口 55 | 56 | 这里,需要界定的功能是,注册相当于插入数据,登录相当于查询数据,用户名查重也是查询功能,其他的功能与数据库操作无关,所以目前也只实现这部分功能。 57 | 58 | 注:如下过程,相关的知识大部分都在前面博客中讲过了,所以有看不懂的可以回顾一下前面的博客。 59 | 60 | ### 第一步,生成`entity`与`dao` 61 | 62 | + 根据`user`表生成`UserEntity` 63 | 64 | 当字段变多时,手工去写不仅工作量较大,并且容易出错,有兴趣的话可以研究一下如何自动将表映射出实体类,因为涉及别的框架的引入,所以这里不去扩展,其实很简单,只需要百度或者google一下即可。 65 | 66 | ``` java 67 | import java.sql.Timestamp; 68 | 69 | /** 70 | * @Author: ToMax 71 | * @Description: 72 | * @Date: Created in 2018/5/4 22:23 73 | */ 74 | public class UserEntity { 75 | private Integer id; 76 | private String name; 77 | private String password; 78 | private Timestamp time; 79 | 80 | public Integer getId() { 81 | return id; 82 | } 83 | 84 | public void setId(Integer id) { 85 | this.id = id; 86 | } 87 | 88 | public String getName() { 89 | return name; 90 | } 91 | 92 | public void setName(String name) { 93 | this.name = name; 94 | } 95 | 96 | public String getPassword() { 97 | return password; 98 | } 99 | 100 | public void setPassword(String password) { 101 | this.password = password; 102 | } 103 | 104 | public Timestamp getTime() { 105 | return time; 106 | } 107 | 108 | public void setTime(Timestamp time) { 109 | this.time = time; 110 | } 111 | } 112 | ``` 113 | 114 | 这里简单提一下的是,数据库中的`datetime`可以在`java`中表述为`Timestamp`类型 115 | 116 | + 完成`IUserDao` 117 | 118 | 生成`IUserDao`接口 119 | 120 | ``` java 121 | import cn.nuaa.tomax.entity.UserEntity; 122 | 123 | import java.util.List; 124 | 125 | /** 126 | * @Author: ToMax 127 | * @Description: 128 | * @Date: Created in 2018/5/4 22:25 129 | */ 130 | public interface IUserDao { 131 | /** 132 | * 新增用户 133 | * @param sql 134 | * @param user 135 | */ 136 | public void saveUser(String sql, UserEntity user); 137 | 138 | /** 139 | * 根据条件获取用户列表 140 | * @param sql 141 | * @param keys 142 | * @return 143 | */ 144 | public List listUsers(String sql, Object[] keys); 145 | } 146 | ``` 147 | 仅简单的定义两个接口 148 | 149 | + 完成`IUserDao`的实现类`UserDaoImpl` 150 | 151 | 在`dao.impl`目录下创建`java`类`UserDaoImpl` 152 | 153 | ``` java 154 | import java.util.List; 155 | 156 | /** 157 | * @Author: ToMax 158 | * @Description: 159 | * @Date: Created in 2018/5/4 22:29 160 | */ 161 | @Repository 162 | public class UserDaoImpl extends DaoHelper implements IUserDao{ 163 | @Override 164 | public void saveUser(String sql, UserEntity user) { 165 | this.insertByBean(sql,user); 166 | } 167 | 168 | @Override 169 | public List listUsers(String sql, Object[] keys) { 170 | return this.query(sql,keys,UserEntity.class); 171 | } 172 | } 173 | ``` 174 | 175 | ### 第二步,实现用户业务 176 | 177 | + 创建`IUserService` 178 | 179 | ``` java 180 | import cn.nuaa.tomax.entity.ResultCause; 181 | import cn.nuaa.tomax.entity.UserEntity; 182 | 183 | /** 184 | * @Author: ToMax 185 | * @Description: 186 | * @Date: Created in 2018/5/4 22:44 187 | */ 188 | public interface IUserService { 189 | /** 190 | * 登录验证 191 | * @param name 192 | * @param password 193 | * @return 194 | */ 195 | public ResultCause checkUser(String name, String password); 196 | 197 | /** 198 | * 用户注册 199 | * @param user 200 | * @return 201 | */ 202 | public ResultCause registerUser(UserEntity user); 203 | } 204 | ``` 205 | 206 | + 完成`IUserService`的实现类`UserServiceImpl` 207 | 208 | 在`service.impl`目录下新建`java`类`UserServiceImpl` 209 | 210 | ``` java 211 | import cn.nuaa.tomax.dao.IUserDao; 212 | import cn.nuaa.tomax.entity.ResultCause; 213 | import cn.nuaa.tomax.entity.UserEntity; 214 | import cn.nuaa.tomax.service.IUserService; 215 | import org.springframework.stereotype.Service; 216 | 217 | import javax.annotation.Resource; 218 | import java.sql.Timestamp; 219 | import java.util.List; 220 | 221 | /** 222 | * @Author: ToMax 223 | * @Description: 224 | * @Date: Created in 2018/5/4 22:48 225 | */ 226 | @Service 227 | public class UserServiceImpl implements IUserService{ 228 | @Resource 229 | private IUserDao userDao; 230 | 231 | @Override 232 | public ResultCause checkUser(String name, String password) { 233 | UserEntity user = getTargetUser(name); 234 | if (user == null){ 235 | //未查到该用户,即用户不存在 236 | return new ResultCause(ResultCause.FAIL_CODE,"用户名或密码错误"); 237 | }else if (user.getPassword().equals(password)){ 238 | //登录验证成功 239 | return new ResultCause(ResultCause.SUCCESS_CODE,"登录成功"); 240 | } 241 | //密码错误 242 | return new ResultCause(ResultCause.FAIL_CODE,"用户名或密码错误"); 243 | } 244 | 245 | @Override 246 | public ResultCause registerUser(UserEntity user) { 247 | if (getTargetUser(user.getName()) != null){ 248 | return new ResultCause(ResultCause.FAIL_CODE,"用户名已存在"); 249 | }else { 250 | //设置注册时间 251 | user.setTime(new Timestamp(System.currentTimeMillis())); 252 | //id为自增字段,所以不需要在这里设置 253 | String sql = "insert into user (name,password,time) values (:name,:password,:time)"; 254 | userDao.saveUser(sql,user); 255 | } 256 | return new ResultCause(ResultCause.SUCCESS_CODE,"注册成功"); 257 | } 258 | 259 | /** 260 | * 根据用户名查找用户,因为本系统用户名唯一,所以用户名查找到的结果为单个用户对象 261 | * 同时,因为在登录验证和注册查重中均有查询用户对象的需求,所以将这部分代码拿出, 262 | * 进行复用 263 | * @param name 264 | * @return 如果查询结果非空,返回唯一的结果,否则返回空值 265 | */ 266 | private UserEntity getTargetUser(String name){ 267 | String sql = "select * from user where name = ?"; 268 | List userEntities = userDao.listUsers(sql,new Object[]{name}); 269 | return (userEntities!=null&&userEntities.size()>0)?userEntities.get(0):null; 270 | } 271 | } 272 | ``` 273 | 274 | 简单介绍一下,这里除了登录注册接口的实现以外,添加了一个获取查询用户的方法,用来简单复用。 275 | 276 | 另外,对于系统中的密码,全部都是明文的,没有进行加密,可以选择自己感兴趣的加密方法,当然,喜欢偷懒,也可以像我这样,直接采用明文的方式。 277 | 278 | ### 第三步,完成`controller` 279 | 280 | 在`controller`目录下新建`UserController` 281 | 282 | ``` java 283 | import cn.nuaa.tomax.entity.ResultCause; 284 | import cn.nuaa.tomax.entity.UserEntity; 285 | import cn.nuaa.tomax.service.IUserService; 286 | import org.springframework.stereotype.Controller; 287 | import org.springframework.web.bind.annotation.RequestMapping; 288 | import org.springframework.web.bind.annotation.RequestMethod; 289 | import org.springframework.web.bind.annotation.ResponseBody; 290 | 291 | import javax.annotation.Resource; 292 | 293 | /** 294 | * @Author: ToMax 295 | * @Description: 296 | * @Date: Created in 2018/5/4 23:41 297 | */ 298 | @Controller 299 | @RequestMapping("/user") 300 | public class UserController { 301 | @Resource 302 | private IUserService userService; 303 | 304 | @RequestMapping(value = "/login", method = {RequestMethod.GET,RequestMethod.POST}) 305 | public @ResponseBody 306 | ResultCause login(String name, String password){ 307 | return userService.checkUser(name,password); 308 | } 309 | 310 | @RequestMapping(value = "/register", method = {RequestMethod.GET,RequestMethod.POST}) 311 | public @ResponseBody 312 | ResultCause register(UserEntity user){ 313 | return userService.registerUser(user); 314 | } 315 | } 316 | ``` 317 | 318 | ### 第四步,测试接口 319 | 320 | 启动服务器 321 | 322 | + 注册接口 323 | 324 | 在地址栏输入`localhost:8080/user/register?name=tomax&password=123456` 325 | 326 | 返回结果 327 | ``` json 328 | {"code":"200","desc":"注册成功"} 329 | ``` 330 | 331 | 在地址栏重复输入`localhost:8080/user/register?name=tomax&password=123456` 332 | 333 | 返回结果 334 | ``` json 335 | {"code":"400","desc":"用户名已存在"} 336 | ``` 337 | 338 | + 登录接口 339 | 340 | 在地址栏输入`localhost:8080/user/login?name=tomax&password=123456` 341 | 342 | 返回结果 343 | ``` json 344 | {"code":"200","desc":"登录成功"} 345 | ``` 346 | 347 | 在地址栏输入`localhost:8080/user/login?name=toma&password=123456` 348 | 349 | 返回结果 350 | ``` json 351 | {"code":"400","desc":"用户名或密码错误"} 352 | ``` 353 | 354 | 在地址栏输入`localhost:8080/user/login?name=tomax&password=12345` 355 | 356 | 返回结果 357 | ``` json 358 | {"code":"400","desc":"用户名或密码错误"} 359 | ``` 360 | 361 | 至此,测试完成 362 | 363 | ## 实现界面 364 | 365 | 关于界面,有两种选择,一种是选择复制我已经实现的界面,另一种是自己实现界面。 366 | 367 | 复制的话,从`web`目录中复制`login.jsp`、`register.jsp`以及`web/js`下的`user`目录、`web/css`目录下的`user`目录 368 | 369 | 自己实现的话,建议如下 370 | 371 | 登录界面有一个`form`,其中有两个`input`、一个`checkbox`(记住密码)、两个`button`,一个是登录按钮,一个是跳转到注册界面的按钮。 372 | 373 | 注册界面有一个`form`,其中有两个`input`、两个`button`,一个注册按钮,一个是跳转到登录界面的按钮。 374 | 375 | 有了界面之后,下面就可以开始进行交互了(因为github上的代码是实现了本篇全部功能的代码,所以,为了按步骤学习,可以从头开始下面提到的文件) 376 | 377 | + 在`web/js/user`下建立`login.js`,如果是自己写的界面,记得引入该js 378 | 379 | 添加如下代码 380 | ``` javascript 381 | //点击跳转到注册界面的事件 382 | function go_to_register() { 383 | window.location.href = "register.jsp" 384 | } 385 | 386 | //点击登录按钮效果(登录按钮的id为`loginBtn`) 387 | $("#loginBtn").on('click',function () { 388 | //按照通过input的id获取填写的值 389 | var username = $('#username').val() 390 | var password = $('#password').val() 391 | var param = {'name':username, 'password':password} 392 | post("user/login",param,function (result) { 393 | if (result.code == "200"){ 394 | window.location.href = "index.jsp" 395 | }else if (result.code == "400"){ 396 | alert(result.desc) 397 | window.location.href = "login.jsp" 398 | }else { 399 | //TODO:处理其他结果 400 | } 401 | }); 402 | }) 403 | ``` 404 | 405 | 主要定义了两个函数,一个用于跳转到注册界面,另一个用于登录请求 406 | 407 | 完成后,重启服务器,默认打开`login.jsp` 408 | 输入用户名密码,一遍正确,一遍错误 409 | 登录正确跳转到`index.jsp` 410 | 登录错误弹窗提示用户名或密码错误 411 | 412 | + 在`web/js/user`下建立`register.js`,如果是自己写的界面,记得引入该js 413 | 414 | 添加如下代码 415 | ``` javascript 416 | function go_to_login() { 417 | window.location.href = "login.jsp" 418 | } 419 | 420 | $("#reg_btn").on('click',function () { 421 | var username = $('#username').val() 422 | var password = $('#password').val() 423 | var param = {'name':username,'password':password} 424 | post('user/register',param,function (result) { 425 | if (result.code == '200'){ 426 | alert(result.desc) 427 | window.location.href = "login.jsp" 428 | }else { 429 | alert(result.desc) 430 | window.location.href = "register.jsp" 431 | } 432 | }) 433 | }) 434 | ``` 435 | 436 | 点击注册按钮时,获取用户名及密码输入框的值,然后设置参数,发送请求到注册接口 437 | 完成后,更新服务器,可以在登录界面点击注册按钮跳转到注册界面 438 | 439 | 首先测试注册一个新的用户后,弹窗注册成功,并跳转至登录界面进行登录操作 440 | 再次测试注册一个已经存在的用户名,弹窗提示用户名已存在,更新注册界面 441 | 442 | 至此,登录注册基本实现。 443 | 444 | ## 实现记住密码功能 445 | 446 | > 简单分析下该功能,需要做的是,当用户选中`checkbox`后,需要记住登录状态,当下一次登录时,不需要再次输入密码信息。当用户没有选中`checkbox`时,清楚该用户的登录状态。 447 | 448 | 这部分代码主要在前端进行实现即可 449 | 450 | 在`login.js`中加入如下代码 451 | ``` javascript 452 | // 获取cookie中相应字段的值 453 | var username = getCookie('demo_username') 454 | var password = getCookie('demo_password') 455 | var flag = getCookie('demo_flag') 456 | $("#username").val(username!=null?username:'') 457 | $("#password").val(password!=null?password:'') 458 | if (flag != null){ 459 | $("#remb").attr('checked','checked') 460 | } 461 | 462 | // 前往注册界面 463 | function go_to_register() { 464 | window.location.href = "register.jsp" 465 | } 466 | 467 | //点击登录按钮效果(登录按钮的id为`loginBtn`) 468 | $("#loginBtn").on('click',function () { 469 | //按照通过input的id获取填写的值 470 | var username = $('#username').val() 471 | var password = $('#password').val() 472 | var param = {'name':username, 'password':password} 473 | post("user/login",param,function (result) { 474 | if (result.code == "200"){ 475 | // 判断是否记住密码 476 | var flag = $('#remb').is(':checked') 477 | if (flag == true){ 478 | //如果记住密码,则将值设置到cookie中去 479 | setCookie('demo_username',username) 480 | setCookie('demo_password',password) 481 | setCookie('demo_flag',flag) 482 | }else { 483 | // 如果忘记,则使相应的cookie值失效 484 | delCookie('demo_username') 485 | delCookie('demo_password') 486 | delCookie('demo_flag') 487 | } 488 | window.location.href = "index.jsp" 489 | }else if (result.code == "400"){ 490 | alert(result.desc) 491 | window.location.href = "login.jsp" 492 | }else { 493 | //TODO:处理其他结果 494 | } 495 | }); 496 | }) 497 | 498 | //设置cookie 499 | function setCookie(name,value) { 500 | var Days = 7 501 | var exp = new Date() 502 | exp.setTime(exp.getTime() + Days*24*60*60*1000) 503 | document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString() 504 | } 505 | // 获取cookie 506 | function getCookie(name) { 507 | var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)"); 508 | if(arr=document.cookie.match(reg)){ 509 | return unescape(arr[2]) 510 | } else{ 511 | return null 512 | } 513 | } 514 | //删除cookies 515 | function delCookie(name) { 516 | var exp = new Date() 517 | exp.setTime(exp.getTime() - 1); 518 | var cval=getCookie(name) 519 | if(cval!=null){ 520 | document.cookie= name + "="+cval+";expires="+exp.toGMTString() 521 | } 522 | } 523 | ``` 524 | 第一部分代码,就是获取已经记住的信息,如果有的话,则将获取的值设置到相应的输入框中 525 | 第二部分代码,就是在原有的登录请求的回调函数中,当登录成功后,就判断是否记住密码,如果是要记住密码,就增加`cookie`记录,否则,删除记录 526 | 第三部分代码,是`cookie`的增、删、查操作 527 | 528 | 重启服务器,试一试,是不是可以记住密码了 529 | 530 | 第一次,刷新登录界面,输入正确的用户名、密码,不选中记住密码 531 | 第二次,刷新登录界面,输入正确的用户名、密码,选中记住密码 532 | 第三次,刷新登录界面,用记住的密码直接登录 533 | 第四次,刷新登录界面,取消选中记住密码,用记住的密码直接登录 534 | 第五次,刷新登录界面,输入错误的用户名密码,登录 535 | 536 | 测试完成 537 | 538 | 539 | + 这里需要在`UserController`中增加两个成员,不过考虑到之后可能还有其他的`controller`也会用到这两个成员,所以,不妨定义一个父类,暂且命名为`SuperAction`,在`controller`目录下创建它 540 | 541 | ``` java 542 | @Controller 543 | public class SuperAction { 544 | protected HttpServletRequest request; 545 | protected HttpServletResponse response; 546 | 547 | @ModelAttribute 548 | public void setReqAndRes(HttpServletRequest request, HttpServletResponse response){ 549 | this.request = request; 550 | this.response = response; 551 | } 552 | } 553 | ``` 554 | 555 | ## 关于登录状态控制即注销功能的实现,在下一篇再提 556 | 557 | [下一篇:简单留言功能的实现](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E7%AE%80%E5%8D%95%E7%95%99%E8%A8%80%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.md) 558 | 559 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 560 | 561 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 562 | 563 | 564 | > 如果有帮助的话,来颗star吧 -------------------------------------------------------------------------------- /blogs/简单留言功能的实现.md: -------------------------------------------------------------------------------- 1 | # 简单留言功能的实现 2 | 3 | **Author : ToMax** 4 | 5 | > 这一篇中,将完成一个功能不完全的留言板功能,同时完成上一篇未完成的登录注销功能 6 | 7 | 关于留言板的功能,这里强行设定,所有用户共用一个留言板,登录后可以添加,未登录只能查看 8 | 9 | ## 建表 10 | 11 | ``` sql 12 | 表名 : message 13 | 字段如下 : 14 | 字段名 数据类型 长度 是否主键 是否自增 备注 15 | id int Y Y 留言的id,唯一主键 16 | user_id int N N 发言人的id 17 | content varchar 128 N N 内容 18 | time datetime N N 发言时间 19 | ... ... ... ... ... 20 | ``` 21 | 22 | 留言人id用于关联用户表的id 23 | 24 | 建表截图如下: 25 | 26 |  27 | 28 | 或者有如下建表语句 29 | ```sql 30 | CREATE TABLE `message` ( 31 | `id` int(11) NOT NULL AUTO_INCREMENT, 32 | `user_id` int(11) DEFAULT NULL, 33 | `content` varchar(128) DEFAULT NULL, 34 | `time` datetime DEFAULT NULL, 35 | PRIMARY KEY (`id`) 36 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 37 | ``` 38 | 39 | ## 完成接口 40 | 41 | + 新建`MessageEntity` 42 | 43 | ``` java 44 | import java.sql.Timestamp; 45 | 46 | /** 47 | * @Author: ToMax 48 | * @Description: 49 | * @Date: Created in 2018/5/5 18:35 50 | */ 51 | public class MessageEntity { 52 | private Integer id; 53 | private Integer userId; 54 | private String name; 55 | private String content; 56 | private Timestamp time; 57 | 58 | public Integer getId() { 59 | return id; 60 | } 61 | 62 | public void setId(Integer id) { 63 | this.id = id; 64 | } 65 | 66 | public Integer getUserId() { 67 | return userId; 68 | } 69 | 70 | public void setUserId(Integer userId) { 71 | this.userId = userId; 72 | } 73 | 74 | public String getName() { 75 | return name; 76 | } 77 | 78 | public void setName(String name) { 79 | this.name = name; 80 | } 81 | 82 | public String getContent() { 83 | return content; 84 | } 85 | 86 | public void setContent(String content) { 87 | this.content = content; 88 | } 89 | 90 | public Timestamp getTime() { 91 | return time; 92 | } 93 | 94 | public void setTime(Timestamp time) { 95 | this.time = time; 96 | } 97 | } 98 | ``` 99 | 100 | 关于多出来的`name`是对应了`user`表里的`name`属性,因为在获取留言内容时,还需要获取留言人的用户名 101 | 102 | + 新建`IMessageDao` 103 | 104 | ``` java 105 | import java.util.List; 106 | /** 107 | * @Author: ToMax 108 | * @Description: 109 | * @Date: Created in 2018/5/5 18:37 110 | */ 111 | public interface IMessageDao { 112 | /** 113 | * 新增留言 114 | * @param sql 115 | * @param message 116 | */ 117 | public void saveMessage(String sql, MessageEntity message); 118 | 119 | /** 120 | * 获取留言 121 | * @param sql 122 | * @param keys 123 | * @return 124 | */ 125 | public List listMsgs(String sql, Object[] keys); 126 | } 127 | ``` 128 | 129 | + 新建`MessageDaoImpl` 130 | 131 | ``` java 132 | import cn.nuaa.tomax.dao.DaoHelper; 133 | import cn.nuaa.tomax.dao.IMessageDao; 134 | import cn.nuaa.tomax.entity.MessageEntity; 135 | import org.springframework.stereotype.Repository; 136 | 137 | import java.util.List; 138 | 139 | /** 140 | * @Author: ToMax 141 | * @Description: 142 | * @Date: Created in 2018/5/5 18:39 143 | */ 144 | @Repository 145 | public class MessageDaoImpl extends DaoHelper implements IMessageDao{ 146 | @Override 147 | public void saveMessage(String sql, MessageEntity message) { 148 | this.insertByBean(sql,message); 149 | } 150 | 151 | @Override 152 | public List listMsgs(String sql, Object[] keys) { 153 | return this.query(sql,keys,MessageEntity.class); 154 | } 155 | } 156 | ``` 157 | 158 | + 新建`IMessageService` 159 | 160 | ``` java 161 | import java.util.List; 162 | 163 | /** 164 | * @Author: ToMax 165 | * @Description: 166 | * @Date: Created in 2018/5/5 18:41 167 | */ 168 | public interface IMessageService { 169 | public ResultCause addMessage(MessageEntity msg); 170 | public List getMsgs(); 171 | } 172 | ``` 173 | 174 | + 新建`MessageServiceImpl` 175 | 176 | ``` java 177 | import cn.nuaa.tomax.dao.IMessageDao; 178 | import cn.nuaa.tomax.entity.MessageEntity; 179 | import cn.nuaa.tomax.entity.ResultCause; 180 | import cn.nuaa.tomax.service.IMessageService; 181 | import org.springframework.stereotype.Service; 182 | 183 | import javax.annotation.Resource; 184 | import java.sql.Timestamp; 185 | import java.util.List; 186 | 187 | /** 188 | * @Author: ToMax 189 | * @Description: 190 | * @Date: Created in 2018/5/5 18:42 191 | */ 192 | @Service 193 | public class MessageServiceImpl implements IMessageService{ 194 | @Resource 195 | private IMessageDao messageDao; 196 | @Override 197 | public ResultCause addMessage(MessageEntity msg) { 198 | msg.setTime(new Timestamp(System.currentTimeMillis())); 199 | String sql = "insert into message (user_id,content,time) values (:userId,:content,:time)"; 200 | messageDao.saveMessage(sql,msg); 201 | return new ResultCause(ResultCause.SUCCESS_CODE,"添加消息成功"); 202 | } 203 | 204 | @Override 205 | public List getMsgs() { 206 | String sql = "select m.id,m.user_id,m.content,m.time,u.name from message as m inner join user as u on (m.user_id = u.id) order by m.time desc"; 207 | return messageDao.listMsgs(sql,new Object[]{}); 208 | } 209 | } 210 | ``` 211 | 212 | 简单说明下获取`message`的那个方法,其中的`sql`语句使用了联合查询,即联合两张表查询内容,如果不想过多的深入学习`sql`,可以还是原来那样的用`select * from message`,然后对于查询的结果进行遍历,然后在遍历的过程中对每一个`message`对象都去用该对象的`userId`成员去`user`表查询`name`。当然,这么做是相对麻烦的,所以这里的方案就是联合查询,使用`inner join`,加入一张表后,用`userId`作为限制条件去获取值。 213 | 214 | 同时处理查询时按照`time`字段作降序排序,以获得一个按照时间排序的留言列表 215 | 216 | + 新建`MessageController` 217 | 218 | ``` java 219 | import cn.nuaa.tomax.entity.MessageEntity; 220 | import cn.nuaa.tomax.entity.ResultCause; 221 | import cn.nuaa.tomax.service.IMessageService; 222 | import org.springframework.stereotype.Controller; 223 | import org.springframework.web.bind.annotation.RequestMapping; 224 | import org.springframework.web.bind.annotation.RequestMethod; 225 | import org.springframework.web.bind.annotation.ResponseBody; 226 | 227 | import javax.annotation.Resource; 228 | import java.util.List; 229 | 230 | /** 231 | * @Author: ToMax 232 | * @Description: 233 | * @Date: Created in 2018/5/5 18:55 234 | */ 235 | @Controller 236 | @RequestMapping("/msg") 237 | public class MessageController { 238 | @Resource 239 | private IMessageService messageService; 240 | 241 | @RequestMapping(value = "/addMsg", method = {RequestMethod.GET,RequestMethod.POST}) 242 | public @ResponseBody 243 | ResultCause addMsg(MessageEntity msg){ 244 | return messageService.addMessage(msg); 245 | } 246 | 247 | @RequestMapping(value = "/getMsgs", method = {RequestMethod.GET,RequestMethod.POST}) 248 | public @ResponseBody 249 | List getMsgs(){ 250 | return messageService.getMsgs(); 251 | } 252 | } 253 | ``` 254 | 255 | + 进行测试 256 | 257 | 启动服务器 258 | 输入`localhost:8080/msg/addMsg?userId=1&content=hello`(user_id可以去数据库user表里看一下) 259 | 输入`localhost:8080/msg/getMsgs` 260 | 261 | 检查返回结果 262 | 263 | ## 完成界面 264 | 265 | 从`web`下拷贝`index.jsp`替换原`web/index.jsp` 266 | 或者复制下列代码到`index.jsp`中(**该页面由addOneG提供,费时10分钟**) 267 | 268 | ``` jsp 269 | <%-- 270 | Created by IntelliJ IDEA. 271 | User: VULCAN 272 | Date: 2018/4/20 273 | Time: 22:16 274 | To change this template use File | Settings | File Templates. 275 | --%> 276 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 277 | 278 | 279 | 280 | 281 | 282 | 留言板 283 | 284 | 325 | 326 | 327 | 328 | 329 | 330 | 留言板 331 | 332 | Username 333 | 334 | Logout 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 提交 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | ``` 353 | 354 | 创建`web/js/message/message.js`,暂时不写内容 355 | 356 | ## 对接 357 | 358 | 在`message.js`完成如下代码 359 | 360 | ``` javascript 361 | //加载留言列表 362 | getMsgListRequest() 363 | 364 | function getMsgListRequest() { 365 | post('msg/getMsgs',[],function (result) { 366 | listHtml = '' 367 | for (var i = 0; i < result.length; i++){ 368 | listHtml += '' 369 | listHtml += ''+result[i].name+'' 370 | listHtml += result[i].content 371 | listHtml += '' 372 | } 373 | $('#msg_list').html(listHtml) 374 | }) 375 | } 376 | 377 | //点击添加留言 378 | $('#msg_btn').on('click',function () { 379 | var content = $('#msg_con').val() 380 | var user_id = 1 381 | var param = {'content':content,'userId':user_id} 382 | post('msg/addMsg',param,function (result) { 383 | alert(result.desc) 384 | //添加完留言后刷新留言板 385 | getMsgListRequest() 386 | }) 387 | }) 388 | ``` 389 | 390 | 这里,注意到需要发送一个`userId`给添加`message`的接口,但是目前是没有记录当前登录用户状态的,所以,这里暂且设其为`1`,之后再做讨论 391 | 392 | 现在,已经可以简单的体验相关的功能了,不过,还没有完成 393 | 394 | ## 完成登录注销功能 395 | 396 | + 记录登录状态 397 | 398 | 想要记录登录的状态,就在登录的时候使用`session`进行记录,关于`session`,可以自行了解 399 | 400 | 在开始之前,需要先实现一个java类,在`controller`里新建`SuperAction` 401 | 402 | ``` java 403 | import org.springframework.stereotype.Controller; 404 | import org.springframework.web.bind.annotation.ModelAttribute; 405 | import javax.servlet.http.HttpServletRequest; 406 | import javax.servlet.http.HttpServletResponse; 407 | 408 | /** 409 | * @Author: ToMax 410 | * @Description: 411 | * @Date: Created in 2018/5/5 15:06 412 | */ 413 | @Controller 414 | public class SuperAction { 415 | protected HttpServletRequest request; 416 | protected HttpServletResponse response; 417 | 418 | @ModelAttribute 419 | public void setReqAndRes(HttpServletRequest request, HttpServletResponse response){ 420 | this.request = request; 421 | this.response = response; 422 | } 423 | } 424 | ``` 425 | 通过该类获取`request`和`response`,其中`request`就可以获取来自客户端请求的信息,`response`设置相应客户端的信息,这里通过`@ModelAttribute`注入`request`和`response` 426 | 427 | 接着,修改`UserController`,使其继承自`SuperAction` 428 | 429 | ``` java 430 | UserController extends SuperAction 431 | ``` 432 | 433 | 在修改`login`方法之前,需要在`IUserService`中添加一个接口 434 | 435 | ``` java 436 | /** 437 | * 通过用户名获取用户信息 438 | * @param name 439 | * @return 440 | */ 441 | public UserEntity getUserInfo(String name); 442 | ``` 443 | 444 | 同时在`UserServiceImpl`中实现该方法 445 | ``` java 446 | @Override 447 | public UserEntity getUserInfo(String name) { 448 | String sql = "select name,id from user where name = ?"; 449 | return userDao.listUsers(sql,new Object[]{name}).get(0); 450 | } 451 | ``` 452 | 453 | 下面修改`UserController`的`login`方法 454 | ``` java 455 | @RequestMapping(value = "/login", method = {RequestMethod.GET,RequestMethod.POST}) 456 | public @ResponseBody 457 | ResultCause login(String name, String password) throws IOException { 458 | ResultCause result = userService.checkUser(name,password); 459 | HttpSession session = request.getSession(); 460 | session.removeAttribute(session.getId()); 461 | if (result.getCode().equals(ResultCause.SUCCESS_CODE)){ 462 | session.setAttribute(session.getId(),userService.getUserInfo(name)); 463 | } 464 | return result; 465 | } 466 | ``` 467 | 468 | + 使用该登录状态 469 | 470 | 在`index.jsp`中作如下修改 471 | 472 | 在进入`index.jsp`时需要判断当前是否登录,如果已登录,则页面右上角应显示用户名和`Logout`,否则显示`未登录`和`Login` 473 | 474 | 且未登录状态下,点击提交时需要提示`需登录后留言` 475 | 476 | 这里要运用`jsp`的一些操作了,`jsp`与`html`比较显著的区别就是`jsp`中可以写`java`代码 477 | 478 | 在``标签上方增加如下代码 479 | ``` jsp 480 | <% 481 | UserEntity user = (UserEntity) session.getAttribute(session.getId()); 482 | String username = "未登录"; 483 | Integer userId = -1; 484 | if (user != null){ 485 | username = user.getName(); 486 | userId = user.getId(); 487 | } 488 | %> 489 | ``` 490 | `java`代码写在`<%%>`中 491 | 492 | 在``上方添加一段`js`代码 493 | 494 | ``` javascript 495 | 501 | ``` 502 | 503 | 在`js/message/message.js`作一些修改 504 | 505 | 一是修改 506 | ``` javascript 507 | $('#msg_btn').on('click',function () { 508 | if (userId == -1){ 509 | alert('留言请先登录') 510 | }else { 511 | var content = $('#msg_con').val() 512 | var param = {'content':content,'userId':userId} 513 | post('msg/addMsg',param,function (result) { 514 | alert(result.desc) 515 | getMsgListRequest() 516 | }) 517 | } 518 | }) 519 | ``` 520 | 为 521 | ``` javascript 522 | $('#msg_btn').on('click',function () { 523 | var content = $('#msg_con').val() 524 | var param = {'content':content,'userId':userId} 525 | post('msg/addMsg',param,function (result) { 526 | alert(result.desc) 527 | getMsgListRequest() 528 | }) 529 | }) 530 | ``` 531 | 532 | 二是增加一个点击事件 533 | 534 | ``` javascript 535 | $('#log').on('click',function () { 536 | if (userId == -1){ 537 | window.location.href = 'login.jsp' 538 | }else { 539 | window.location.href = 'logout.jsp' 540 | } 541 | }) 542 | ``` 543 | 544 | 这里需要在`web`目录下创建一个`logout.jsp`,使用`jsp`注销登录状态 545 | 546 | ``` jsp 547 | <%-- 548 | Created by IntelliJ IDEA. 549 | User: VULCAN 550 | Date: 2018/2/23 551 | Time: 20:28 552 | To change this template use File | Settings | File Templates. 553 | --%> 554 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 555 | 556 | 557 | 注销 558 | <% 559 | session.invalidate(); 560 | out.print(""); 561 | %> 562 | 563 | 564 | 565 | 566 | ``` 567 | 568 | `session.invalidate()`用来注销登录状态,同时跳转回主页 569 | 570 | 最后,修改`web/WEB-INF/web.xml`,默认访问主页 571 | ``` xml 572 | 573 | index.jsp 574 | 575 | ``` 576 | 577 | 重启服务器。预定的功能已基本完成 578 | 579 | ## 小结 580 | 581 | 可以看到,这里的留言板功能过于简单,一方面是因为本人时间比较紧张了,另一方面也是给学习的同学一些自由发挥的地方,还可以有很多很多的想法在留言板的功能中。 582 | 583 | [回到目录](https://github.com/XingToMax/DesignPatternDemo/tree/master/blogs) 584 | 585 | [问题跟踪和更新说明](https://github.com/XingToMax/DesignPatternDemo/blob/master/blogs/%E9%97%AE%E9%A2%98%E8%B7%9F%E8%B8%AA%E5%92%8C%E6%9B%B4%E6%96%B0%E8%AF%B4%E6%98%8E.md) 586 | 587 | 588 | > 如果有帮助的话,来颗star吧 589 | 590 | -------------------------------------------------------------------------------- /web/css/bootstrap/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /web/css/bootstrap/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:'FontAwesome';src:url('../../fonts/fontawesome-webfont.eot?v=3.2.1');src:url('../../fonts/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../../fonts/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../../fonts/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../../fonts/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal;}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;} 2 | [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none;} 3 | .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em;} 4 | a [class^="icon-"],a [class*=" icon-"]{display:inline;} 5 | [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:0.2857142857142857em;}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em;} 6 | .icons-ul{margin-left:2.142857142857143em;list-style-type:none;}.icons-ul>li{position:relative;} 7 | .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit;} 8 | [class^="icon-"].hide,[class*=" icon-"].hide{display:none;} 9 | .icon-muted{color:#eeeeee;} 10 | .icon-light{color:#ffffff;} 11 | .icon-dark{color:#333333;} 12 | .icon-border{border:solid 1px #eeeeee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} 13 | .icon-2x{font-size:2em;}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} 14 | .icon-3x{font-size:3em;}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} 15 | .icon-4x{font-size:4em;}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} 16 | .icon-5x{font-size:5em;}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;} 17 | .pull-right{float:right;} 18 | .pull-left{float:left;} 19 | [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em;} 20 | [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em;} 21 | [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;} 22 | .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none;} 23 | .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em;} 24 | .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block;} 25 | .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em;} 26 | .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em;} 27 | .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em;} 28 | .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em;} 29 | .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0;}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em;} 30 | .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em;} 31 | .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em;} 32 | .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit;} 33 | .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%;}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em;} 34 | .icon-stack .icon-stack-base{font-size:2em;*line-height:1em;} 35 | .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;} 36 | a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none;} 37 | @-moz-keyframes spin{0%{-moz-transform:rotate(0deg);} 100%{-moz-transform:rotate(359deg);}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);} 100%{-webkit-transform:rotate(359deg);}}@-o-keyframes spin{0%{-o-transform:rotate(0deg);} 100%{-o-transform:rotate(359deg);}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg);} 100%{-ms-transform:rotate(359deg);}}@keyframes spin{0%{transform:rotate(0deg);} 100%{transform:rotate(359deg);}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);} 38 | .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);} 39 | .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);} 40 | .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1);} 41 | .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1);} 42 | a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block;} 43 | .icon-glass:before{content:"\f000";} 44 | .icon-music:before{content:"\f001";} 45 | .icon-search:before{content:"\f002";} 46 | .icon-envelope-alt:before{content:"\f003";} 47 | .icon-heart:before{content:"\f004";} 48 | .icon-star:before{content:"\f005";} 49 | .icon-star-empty:before{content:"\f006";} 50 | .icon-user:before{content:"\f007";} 51 | .icon-film:before{content:"\f008";} 52 | .icon-th-large:before{content:"\f009";} 53 | .icon-th:before{content:"\f00a";} 54 | .icon-th-list:before{content:"\f00b";} 55 | .icon-ok:before{content:"\f00c";} 56 | .icon-remove:before{content:"\f00d";} 57 | .icon-zoom-in:before{content:"\f00e";} 58 | .icon-zoom-out:before{content:"\f010";} 59 | .icon-power-off:before,.icon-off:before{content:"\f011";} 60 | .icon-signal:before{content:"\f012";} 61 | .icon-gear:before,.icon-cog:before{content:"\f013";} 62 | .icon-trash:before{content:"\f014";} 63 | .icon-home:before{content:"\f015";} 64 | .icon-file-alt:before{content:"\f016";} 65 | .icon-time:before{content:"\f017";} 66 | .icon-road:before{content:"\f018";} 67 | .icon-download-alt:before{content:"\f019";} 68 | .icon-download:before{content:"\f01a";} 69 | .icon-upload:before{content:"\f01b";} 70 | .icon-inbox:before{content:"\f01c";} 71 | .icon-play-circle:before{content:"\f01d";} 72 | .icon-rotate-right:before,.icon-repeat:before{content:"\f01e";} 73 | .icon-refresh:before{content:"\f021";} 74 | .icon-list-alt:before{content:"\f022";} 75 | .icon-lock:before{content:"\f023";} 76 | .icon-flag:before{content:"\f024";} 77 | .icon-headphones:before{content:"\f025";} 78 | .icon-volume-off:before{content:"\f026";} 79 | .icon-volume-down:before{content:"\f027";} 80 | .icon-volume-up:before{content:"\f028";} 81 | .icon-qrcode:before{content:"\f029";} 82 | .icon-barcode:before{content:"\f02a";} 83 | .icon-tag:before{content:"\f02b";} 84 | .icon-tags:before{content:"\f02c";} 85 | .icon-book:before{content:"\f02d";} 86 | .icon-bookmark:before{content:"\f02e";} 87 | .icon-print:before{content:"\f02f";} 88 | .icon-camera:before{content:"\f030";} 89 | .icon-font:before{content:"\f031";} 90 | .icon-bold:before{content:"\f032";} 91 | .icon-italic:before{content:"\f033";} 92 | .icon-text-height:before{content:"\f034";} 93 | .icon-text-width:before{content:"\f035";} 94 | .icon-align-left:before{content:"\f036";} 95 | .icon-align-center:before{content:"\f037";} 96 | .icon-align-right:before{content:"\f038";} 97 | .icon-align-justify:before{content:"\f039";} 98 | .icon-list:before{content:"\f03a";} 99 | .icon-indent-left:before{content:"\f03b";} 100 | .icon-indent-right:before{content:"\f03c";} 101 | .icon-facetime-video:before{content:"\f03d";} 102 | .icon-picture:before{content:"\f03e";} 103 | .icon-pencil:before{content:"\f040";} 104 | .icon-map-marker:before{content:"\f041";} 105 | .icon-adjust:before{content:"\f042";} 106 | .icon-tint:before{content:"\f043";} 107 | .icon-edit:before{content:"\f044";} 108 | .icon-share:before{content:"\f045";} 109 | .icon-check:before{content:"\f046";} 110 | .icon-move:before{content:"\f047";} 111 | .icon-step-backward:before{content:"\f048";} 112 | .icon-fast-backward:before{content:"\f049";} 113 | .icon-backward:before{content:"\f04a";} 114 | .icon-play:before{content:"\f04b";} 115 | .icon-pause:before{content:"\f04c";} 116 | .icon-stop:before{content:"\f04d";} 117 | .icon-forward:before{content:"\f04e";} 118 | .icon-fast-forward:before{content:"\f050";} 119 | .icon-step-forward:before{content:"\f051";} 120 | .icon-eject:before{content:"\f052";} 121 | .icon-chevron-left:before{content:"\f053";} 122 | .icon-chevron-right:before{content:"\f054";} 123 | .icon-plus-sign:before{content:"\f055";} 124 | .icon-minus-sign:before{content:"\f056";} 125 | .icon-remove-sign:before{content:"\f057";} 126 | .icon-ok-sign:before{content:"\f058";} 127 | .icon-question-sign:before{content:"\f059";} 128 | .icon-info-sign:before{content:"\f05a";} 129 | .icon-screenshot:before{content:"\f05b";} 130 | .icon-remove-circle:before{content:"\f05c";} 131 | .icon-ok-circle:before{content:"\f05d";} 132 | .icon-ban-circle:before{content:"\f05e";} 133 | .icon-arrow-left:before{content:"\f060";} 134 | .icon-arrow-right:before{content:"\f061";} 135 | .icon-arrow-up:before{content:"\f062";} 136 | .icon-arrow-down:before{content:"\f063";} 137 | .icon-mail-forward:before,.icon-share-alt:before{content:"\f064";} 138 | .icon-resize-full:before{content:"\f065";} 139 | .icon-resize-small:before{content:"\f066";} 140 | .icon-plus:before{content:"\f067";} 141 | .icon-minus:before{content:"\f068";} 142 | .icon-asterisk:before{content:"\f069";} 143 | .icon-exclamation-sign:before{content:"\f06a";} 144 | .icon-gift:before{content:"\f06b";} 145 | .icon-leaf:before{content:"\f06c";} 146 | .icon-fire:before{content:"\f06d";} 147 | .icon-eye-open:before{content:"\f06e";} 148 | .icon-eye-close:before{content:"\f070";} 149 | .icon-warning-sign:before{content:"\f071";} 150 | .icon-plane:before{content:"\f072";} 151 | .icon-calendar:before{content:"\f073";} 152 | .icon-random:before{content:"\f074";} 153 | .icon-comment:before{content:"\f075";} 154 | .icon-magnet:before{content:"\f076";} 155 | .icon-chevron-up:before{content:"\f077";} 156 | .icon-chevron-down:before{content:"\f078";} 157 | .icon-retweet:before{content:"\f079";} 158 | .icon-shopping-cart:before{content:"\f07a";} 159 | .icon-folder-close:before{content:"\f07b";} 160 | .icon-folder-open:before{content:"\f07c";} 161 | .icon-resize-vertical:before{content:"\f07d";} 162 | .icon-resize-horizontal:before{content:"\f07e";} 163 | .icon-bar-chart:before{content:"\f080";} 164 | .icon-twitter-sign:before{content:"\f081";} 165 | .icon-facebook-sign:before{content:"\f082";} 166 | .icon-camera-retro:before{content:"\f083";} 167 | .icon-key:before{content:"\f084";} 168 | .icon-gears:before,.icon-cogs:before{content:"\f085";} 169 | .icon-comments:before{content:"\f086";} 170 | .icon-thumbs-up-alt:before{content:"\f087";} 171 | .icon-thumbs-down-alt:before{content:"\f088";} 172 | .icon-star-half:before{content:"\f089";} 173 | .icon-heart-empty:before{content:"\f08a";} 174 | .icon-signout:before{content:"\f08b";} 175 | .icon-linkedin-sign:before{content:"\f08c";} 176 | .icon-pushpin:before{content:"\f08d";} 177 | .icon-external-link:before{content:"\f08e";} 178 | .icon-signin:before{content:"\f090";} 179 | .icon-trophy:before{content:"\f091";} 180 | .icon-github-sign:before{content:"\f092";} 181 | .icon-upload-alt:before{content:"\f093";} 182 | .icon-lemon:before{content:"\f094";} 183 | .icon-phone:before{content:"\f095";} 184 | .icon-unchecked:before,.icon-check-empty:before{content:"\f096";} 185 | .icon-bookmark-empty:before{content:"\f097";} 186 | .icon-phone-sign:before{content:"\f098";} 187 | .icon-twitter:before{content:"\f099";} 188 | .icon-facebook:before{content:"\f09a";} 189 | .icon-github:before{content:"\f09b";} 190 | .icon-unlock:before{content:"\f09c";} 191 | .icon-credit-card:before{content:"\f09d";} 192 | .icon-rss:before{content:"\f09e";} 193 | .icon-hdd:before{content:"\f0a0";} 194 | .icon-bullhorn:before{content:"\f0a1";} 195 | .icon-bell:before{content:"\f0a2";} 196 | .icon-certificate:before{content:"\f0a3";} 197 | .icon-hand-right:before{content:"\f0a4";} 198 | .icon-hand-left:before{content:"\f0a5";} 199 | .icon-hand-up:before{content:"\f0a6";} 200 | .icon-hand-down:before{content:"\f0a7";} 201 | .icon-circle-arrow-left:before{content:"\f0a8";} 202 | .icon-circle-arrow-right:before{content:"\f0a9";} 203 | .icon-circle-arrow-up:before{content:"\f0aa";} 204 | .icon-circle-arrow-down:before{content:"\f0ab";} 205 | .icon-globe:before{content:"\f0ac";} 206 | .icon-wrench:before{content:"\f0ad";} 207 | .icon-tasks:before{content:"\f0ae";} 208 | .icon-filter:before{content:"\f0b0";} 209 | .icon-briefcase:before{content:"\f0b1";} 210 | .icon-fullscreen:before{content:"\f0b2";} 211 | .icon-group:before{content:"\f0c0";} 212 | .icon-link:before{content:"\f0c1";} 213 | .icon-cloud:before{content:"\f0c2";} 214 | .icon-beaker:before{content:"\f0c3";} 215 | .icon-cut:before{content:"\f0c4";} 216 | .icon-copy:before{content:"\f0c5";} 217 | .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6";} 218 | .icon-save:before{content:"\f0c7";} 219 | .icon-sign-blank:before{content:"\f0c8";} 220 | .icon-reorder:before{content:"\f0c9";} 221 | .icon-list-ul:before{content:"\f0ca";} 222 | .icon-list-ol:before{content:"\f0cb";} 223 | .icon-strikethrough:before{content:"\f0cc";} 224 | .icon-underline:before{content:"\f0cd";} 225 | .icon-table:before{content:"\f0ce";} 226 | .icon-magic:before{content:"\f0d0";} 227 | .icon-truck:before{content:"\f0d1";} 228 | .icon-pinterest:before{content:"\f0d2";} 229 | .icon-pinterest-sign:before{content:"\f0d3";} 230 | .icon-google-plus-sign:before{content:"\f0d4";} 231 | .icon-google-plus:before{content:"\f0d5";} 232 | .icon-money:before{content:"\f0d6";} 233 | .icon-caret-down:before{content:"\f0d7";} 234 | .icon-caret-up:before{content:"\f0d8";} 235 | .icon-caret-left:before{content:"\f0d9";} 236 | .icon-caret-right:before{content:"\f0da";} 237 | .icon-columns:before{content:"\f0db";} 238 | .icon-sort:before{content:"\f0dc";} 239 | .icon-sort-down:before{content:"\f0dd";} 240 | .icon-sort-up:before{content:"\f0de";} 241 | .icon-envelope:before{content:"\f0e0";} 242 | .icon-linkedin:before{content:"\f0e1";} 243 | .icon-rotate-left:before,.icon-undo:before{content:"\f0e2";} 244 | .icon-legal:before{content:"\f0e3";} 245 | .icon-dashboard:before{content:"\f0e4";} 246 | .icon-comment-alt:before{content:"\f0e5";} 247 | .icon-comments-alt:before{content:"\f0e6";} 248 | .icon-bolt:before{content:"\f0e7";} 249 | .icon-sitemap:before{content:"\f0e8";} 250 | .icon-umbrella:before{content:"\f0e9";} 251 | .icon-paste:before{content:"\f0ea";} 252 | .icon-lightbulb:before{content:"\f0eb";} 253 | .icon-exchange:before{content:"\f0ec";} 254 | .icon-cloud-download:before{content:"\f0ed";} 255 | .icon-cloud-upload:before{content:"\f0ee";} 256 | .icon-user-md:before{content:"\f0f0";} 257 | .icon-stethoscope:before{content:"\f0f1";} 258 | .icon-suitcase:before{content:"\f0f2";} 259 | .icon-bell-alt:before{content:"\f0f3";} 260 | .icon-coffee:before{content:"\f0f4";} 261 | .icon-food:before{content:"\f0f5";} 262 | .icon-file-text-alt:before{content:"\f0f6";} 263 | .icon-building:before{content:"\f0f7";} 264 | .icon-hospital:before{content:"\f0f8";} 265 | .icon-ambulance:before{content:"\f0f9";} 266 | .icon-medkit:before{content:"\f0fa";} 267 | .icon-fighter-jet:before{content:"\f0fb";} 268 | .icon-beer:before{content:"\f0fc";} 269 | .icon-h-sign:before{content:"\f0fd";} 270 | .icon-plus-sign-alt:before{content:"\f0fe";} 271 | .icon-double-angle-left:before{content:"\f100";} 272 | .icon-double-angle-right:before{content:"\f101";} 273 | .icon-double-angle-up:before{content:"\f102";} 274 | .icon-double-angle-down:before{content:"\f103";} 275 | .icon-angle-left:before{content:"\f104";} 276 | .icon-angle-right:before{content:"\f105";} 277 | .icon-angle-up:before{content:"\f106";} 278 | .icon-angle-down:before{content:"\f107";} 279 | .icon-desktop:before{content:"\f108";} 280 | .icon-laptop:before{content:"\f109";} 281 | .icon-tablet:before{content:"\f10a";} 282 | .icon-mobile-phone:before{content:"\f10b";} 283 | .icon-circle-blank:before{content:"\f10c";} 284 | .icon-quote-left:before{content:"\f10d";} 285 | .icon-quote-right:before{content:"\f10e";} 286 | .icon-spinner:before{content:"\f110";} 287 | .icon-circle:before{content:"\f111";} 288 | .icon-mail-reply:before,.icon-reply:before{content:"\f112";} 289 | .icon-github-alt:before{content:"\f113";} 290 | .icon-folder-close-alt:before{content:"\f114";} 291 | .icon-folder-open-alt:before{content:"\f115";} 292 | .icon-expand-alt:before{content:"\f116";} 293 | .icon-collapse-alt:before{content:"\f117";} 294 | .icon-smile:before{content:"\f118";} 295 | .icon-frown:before{content:"\f119";} 296 | .icon-meh:before{content:"\f11a";} 297 | .icon-gamepad:before{content:"\f11b";} 298 | .icon-keyboard:before{content:"\f11c";} 299 | .icon-flag-alt:before{content:"\f11d";} 300 | .icon-flag-checkered:before{content:"\f11e";} 301 | .icon-terminal:before{content:"\f120";} 302 | .icon-code:before{content:"\f121";} 303 | .icon-reply-all:before{content:"\f122";} 304 | .icon-mail-reply-all:before{content:"\f122";} 305 | .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123";} 306 | .icon-location-arrow:before{content:"\f124";} 307 | .icon-crop:before{content:"\f125";} 308 | .icon-code-fork:before{content:"\f126";} 309 | .icon-unlink:before{content:"\f127";} 310 | .icon-question:before{content:"\f128";} 311 | .icon-info:before{content:"\f129";} 312 | .icon-exclamation:before{content:"\f12a";} 313 | .icon-superscript:before{content:"\f12b";} 314 | .icon-subscript:before{content:"\f12c";} 315 | .icon-eraser:before{content:"\f12d";} 316 | .icon-puzzle-piece:before{content:"\f12e";} 317 | .icon-microphone:before{content:"\f130";} 318 | .icon-microphone-off:before{content:"\f131";} 319 | .icon-shield:before{content:"\f132";} 320 | .icon-calendar-empty:before{content:"\f133";} 321 | .icon-fire-extinguisher:before{content:"\f134";} 322 | .icon-rocket:before{content:"\f135";} 323 | .icon-maxcdn:before{content:"\f136";} 324 | .icon-chevron-sign-left:before{content:"\f137";} 325 | .icon-chevron-sign-right:before{content:"\f138";} 326 | .icon-chevron-sign-up:before{content:"\f139";} 327 | .icon-chevron-sign-down:before{content:"\f13a";} 328 | .icon-html5:before{content:"\f13b";} 329 | .icon-css3:before{content:"\f13c";} 330 | .icon-anchor:before{content:"\f13d";} 331 | .icon-unlock-alt:before{content:"\f13e";} 332 | .icon-bullseye:before{content:"\f140";} 333 | .icon-ellipsis-horizontal:before{content:"\f141";} 334 | .icon-ellipsis-vertical:before{content:"\f142";} 335 | .icon-rss-sign:before{content:"\f143";} 336 | .icon-play-sign:before{content:"\f144";} 337 | .icon-ticket:before{content:"\f145";} 338 | .icon-minus-sign-alt:before{content:"\f146";} 339 | .icon-check-minus:before{content:"\f147";} 340 | .icon-level-up:before{content:"\f148";} 341 | .icon-level-down:before{content:"\f149";} 342 | .icon-check-sign:before{content:"\f14a";} 343 | .icon-edit-sign:before{content:"\f14b";} 344 | .icon-external-link-sign:before{content:"\f14c";} 345 | .icon-share-sign:before{content:"\f14d";} 346 | .icon-compass:before{content:"\f14e";} 347 | .icon-collapse:before{content:"\f150";} 348 | .icon-collapse-top:before{content:"\f151";} 349 | .icon-expand:before{content:"\f152";} 350 | .icon-euro:before,.icon-eur:before{content:"\f153";} 351 | .icon-gbp:before{content:"\f154";} 352 | .icon-dollar:before,.icon-usd:before{content:"\f155";} 353 | .icon-rupee:before,.icon-inr:before{content:"\f156";} 354 | .icon-yen:before,.icon-jpy:before{content:"\f157";} 355 | .icon-renminbi:before,.icon-cny:before{content:"\f158";} 356 | .icon-won:before,.icon-krw:before{content:"\f159";} 357 | .icon-bitcoin:before,.icon-btc:before{content:"\f15a";} 358 | .icon-file:before{content:"\f15b";} 359 | .icon-file-text:before{content:"\f15c";} 360 | .icon-sort-by-alphabet:before{content:"\f15d";} 361 | .icon-sort-by-alphabet-alt:before{content:"\f15e";} 362 | .icon-sort-by-attributes:before{content:"\f160";} 363 | .icon-sort-by-attributes-alt:before{content:"\f161";} 364 | .icon-sort-by-order:before{content:"\f162";} 365 | .icon-sort-by-order-alt:before{content:"\f163";} 366 | .icon-thumbs-up:before{content:"\f164";} 367 | .icon-thumbs-down:before{content:"\f165";} 368 | .icon-youtube-sign:before{content:"\f166";} 369 | .icon-youtube:before{content:"\f167";} 370 | .icon-xing:before{content:"\f168";} 371 | .icon-xing-sign:before{content:"\f169";} 372 | .icon-youtube-play:before{content:"\f16a";} 373 | .icon-dropbox:before{content:"\f16b";} 374 | .icon-stackexchange:before{content:"\f16c";} 375 | .icon-instagram:before{content:"\f16d";} 376 | .icon-flickr:before{content:"\f16e";} 377 | .icon-adn:before{content:"\f170";} 378 | .icon-bitbucket:before{content:"\f171";} 379 | .icon-bitbucket-sign:before{content:"\f172";} 380 | .icon-tumblr:before{content:"\f173";} 381 | .icon-tumblr-sign:before{content:"\f174";} 382 | .icon-long-arrow-down:before{content:"\f175";} 383 | .icon-long-arrow-up:before{content:"\f176";} 384 | .icon-long-arrow-left:before{content:"\f177";} 385 | .icon-long-arrow-right:before{content:"\f178";} 386 | .icon-apple:before{content:"\f179";} 387 | .icon-windows:before{content:"\f17a";} 388 | .icon-android:before{content:"\f17b";} 389 | .icon-linux:before{content:"\f17c";} 390 | .icon-dribbble:before{content:"\f17d";} 391 | .icon-skype:before{content:"\f17e";} 392 | .icon-foursquare:before{content:"\f180";} 393 | .icon-trello:before{content:"\f181";} 394 | .icon-female:before{content:"\f182";} 395 | .icon-male:before{content:"\f183";} 396 | .icon-gittip:before{content:"\f184";} 397 | .icon-sun:before{content:"\f185";} 398 | .icon-moon:before{content:"\f186";} 399 | .icon-archive:before{content:"\f187";} 400 | .icon-bug:before{content:"\f188";} 401 | .icon-vk:before{content:"\f189";} 402 | .icon-weibo:before{content:"\f18a";} 403 | .icon-renren:before{content:"\f18b";} 404 | --------------------------------------------------------------------------------