本文目录:
- 效果
- 工具
- 包
- `src/main/java`
- `src/main/resources`
- `src/main/webapp`
- `src/test/java`
- 代码分析
- 数据库层
- dao层
- domain层
- service层
- servlet层
- BaseServlet.java
- UserServlet.java
- 工具类
- 视图层
- index.html
- index.css
- index.js
- pom.xml配置
- 总结
效果
本文按照我自己写代码的顺序来行文
maven+idea实现登录功能效果图
工具
- jdk13.0.2
- Maven 3.6.3
- idea
包
src/main/java
-
dao
:保存实现访问数据库功能的文件 -
domain
:保存JavaBean文件 -
service
:service层 -
servlet
:servlet层 -
utils
:存放一些工具类
src/main/resources
-
druid.properties
:JDBC配置文件
src/main/webapp
- 存放html、css和js文件
src/test/java
- 主要测试了一下访问数据库的功能是否正常
代码分析
- 按照
dao层
、service层
、servlet层
的顺序
数据库层
CREATE DATABASE day0429;
USE day0429;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
dao层
- UserDao接口
只有一个方法,根据从登录页面获取的用户名和密码查询数据库
User findByUsernameAndPassword(String username, String password);
- UserDaoImpl实现类
public class UserDaoImpl implements UserDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public User findByUsernameAndPassword(String username, String password) {
User user = null;
// user查询失败后会抛异常并终止,try catch一下保证方法返回null
try {
String sql = "select * from user where username = ? and password = ?";
user = template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class), username, password);
} catch (DataAccessException e) {}
return user;
}
}
domain层
- User类
简便起见,只有三个字段,实现注册功能的时候可以再扩充。
还需要生成getter、setter方法。
为了测试使用,生成toString方法。
private int id;
private String username;
private String password;
- ResultInfo.java
这个类的功能是在servlet中保存用户登录的信息,将来可以传递给js,js再写入html页面中
private boolean flag;
private Object data;
private String errorMsg;
service层
- UserService接口
只提供login的方法,由UserServiceImpl.java来实现其功能
User login(User user);
- UserServiceImpl.java
service层存在的意义就是,调用dao层一些基础的方法,来实现更复杂的功能,向servlet层提供更好的服务。
所以这里的login方法调用了dao层实现类的方法,完成查询功能。
private UserDao userDao = new UserDaoImpl();
@Override
public User login(User user) {
return userDao.findByUsernameAndPassword(user.getUsername(), user.getPassword());
}
servlet层
这里把servlet抽取出了BaseServlet,将来就让实现具体功能的servlet去继承它。
BaseServlet.java
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
try {
/*
这里的this,是调用方法的对象,例如有一个路径为`/user/*`的
UserServlet继承了BaseServlet,在UserServlet中有一个login
方法,那么浏览器访问`/user/login`的时候,就会调用
BaseServlet的service方法
*/
Method method = this.getClass().getMethod(methodName,
HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this, req, resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
// writeValue是自定义的一个方法,用于把obj对象序列化为json,并返回给客户端
public void writeValue(HttpServletResponse response, Object obj) throws IOException {
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(), obj);
}
// 功能同writeValue(),返回的是字符串形式的json
public String writeValueAsString(Object obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
}
}
UserServlet.java
// 只要访问路径末尾处含/user/的,都归它管😁
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {
private UserService service = new UserServiceImpl();
/*
根据用户输入的用户名和密码,封装为一个User对象,
将来把这个对象传递给service层的login方法,
查询数据库中有无此用户
*/
private User preProcessUser(HttpServletRequest request) {
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return user;
}
// 用于完成登录验证的工作,把返回的消息序列化为json返回给客户端
public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = preProcessUser(request);
User u = service.login(user);
ResultInfo info;
if (u == null) {
info = new ResultInfo(false, "用户名或密码错误");
} else {
info = new ResultInfo(true);
HttpSession session = request.getSession();
session.setAttribute("user", u);
}
writeValue(response, info);
}
public void getUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = (User) request.getSession().getAttribute("user");
writeValue(response, user);
}
}
工具类
JDBCUtils.java
,此处不再赘述,会附上源代码文件
视图层
这一层简单介绍一下html、css和js文件。
index.html
由于本文主题是登录案例,故index.html就直接作为登录页面了。
wrap盒子作为父盒子,是为了方便使用伸缩盒子。
<div class="wrap">
<div class="title" id="title">Welcome</div>
<form action="" method="post" id="login-form">
<input type="text"name="username" id="username" placeholder="登录" >
<input type="password" name="password" id="password" placeholder="密码">
<input type="button" value="立即登录" id="login-btn">
</form>
<div class="help">
<a href="#">忘记密码</a>
<i></i>
<a href="#">立即注册</a>
</div>
</div>
index.css
使用了less+rem布局,利用flex.js进行媒体查询。由于flex.js是把整个页面划分为10份,所以html的根字号是psd图宽度除以10。只适配了移动端,在PC端显示有问题。
以下贴出的是由less生成的css代码,less的被我手残删了。。
- 分享一个做rem适配小技巧:
- 先做pc端的页面,用像素表示。
- 在less文件的开头给出html的根字号,以宽640px的psd图为例,html根字号就是:
@size: 640px / 10;
- 再选中所有的px,把它替换为
rem / @size;
@size那里的640px不要替换单位哦。
html {
height: 100%;
}
body {
height: 100%;
/*
背景渐变的本质是用渐变色模拟一张背景图像,
故应该用background-image,此处用了background简写
*/
background: linear-gradient(135deg, #6cc9b6, #3878ca) no-repeat;
}
.wrap,
form {
display: flex;
flex-direction: column;
align-items: center;
}
.title {
padding: 4.5625rem 0 1.890625rem;
font-size: 1.40625rem;
color: #fff;
}
form input {
width: 7.5rem;
height: 1.25rem;
padding-left: 0.46875rem;
box-sizing: border-box;
margin-bottom: 0.53125rem;
background-color: transparent;
border: 0.015625rem solid #fff;
border-radius: 0.625rem;
font-size: 0.40625rem;
color: #fff;
}
form input::placeholder {
color: rgba(255, 255, 255, 0.5);
}
form input[type="button"] {
padding-left: 0;
background-color: #56b3f5;
font-size: 0.5rem;
border: 0 none;
}
.help {
display: flex;
justify-content: space-between;
position: relative;
width: 3.4375rem;
height: 0.390625rem;
}
.help a {
text-align: center;
font-size: 0.3125rem;
color: rgba(255, 255, 255, 0.5);
}
.help i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0.015625rem;
height: 0.3125rem;
background-color: #fff;
}
index.js
$.get()
和$.post()
是jQuery提供的实现ajax的函数,故不要忘记导入jQuery
$(function () {
$("#login-btn").click(function () {
$.post("user/login", $("#login-form").serialize(), function (data) {
if (data.flag) {
location.href = "index_ok.html";
} else {
$("#title").html(data.errorMsg);
// 若登录失败,则调整字体大小。因为我的错误提示字数较多
$("#title").css("font-size", "1rem");
}
});
});
});
pom.xml配置
这个怎么可能少得了~😜
其它都是常规配置,我这里只讲一下tomcat7-maven-plugin
的配置
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 配置Tomcat9 -->
<server>tomcat9</server>
<update>true</update>
</configuration>
</plugin>
总结
这个案例还是蛮简单的,不过它对业务代码层次的划分还是让我觉得很有学习意义的。