下面是本项目所使用的工具和技术:
工具:Eclipse + MongoChef + Tomcat8
技术: Servlet+JSP+JavaBean + Maven + Mongdb + Gson + JSTL
1 首先搭建web项目,不添加任何依赖(以防出错,便于排查)
1.1 先创建一个Maven项目,记住选择webapp。如下图所示。
1.2 对新创建的web项目做相应修改(如果不存在以下错误或问题,可跳过),如下图所示。
1.3 创建一个空的index.jsp
1.4 启动server,访问http://localhost:8080/servlet-jsp-javabean/。如无错误,证明web项目已创建好。
2 Servlet+JSP+JavaBean (MVC ) 开发web应用
Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据。 Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式。
2.1 在pom.xml添加jar依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.8.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2.2 创建包层次
2.4 分层架构的代码编写
2.4.1 开发entity层
public class User implements Serializable {
private static final long serialVersionUID = 1L;
// 用户名
private String userName;
// 用户密码
private String userPwd;
// 用户邮箱
private String email;
// 用户生日
private Date birthday;
set/get省略
}
2.4.2 开发数据访问层dao
public interface IUserDao {
void add(User user);
User find(String userName, String userPwd);
User find(String userName);
}
public class UserDaoImpl implements IUserDao {
private DBCollection userdb = MongdbUtil.getDBCollection("user");
private Gson gson = new Gson();
@Override
public void add(User user) {
userdb.save((DBObject) JSON.parse(gson.toJson(user)));// 存入值
}
@Override
public User find(String userName, String userPwd) {
BasicDBObject query = new BasicDBObject();
query.put("userName", userName);
query.put("userPwd", userPwd);
DBCursor cursor = userdb.find(query);
while (cursor.hasNext()) {
return gson.fromJson(cursor.next().toString(), User.class);
}
return null;
}
@Override
public User find(String userName) {
BasicDBObject query = new BasicDBObject();
query.put("userName", userName);
DBCursor cursor = userdb.find(query);
while (cursor.hasNext()) {
return gson.fromJson(cursor.next().toString(), User.class);
}
return null;
}
}
2.4.3 开发service层
public interface IUserService {
void registerUser(User user);
User loginUser(String userName, String userPwd);
}
public class UserServiceImpl implements IUserService {
private IUserDao userDao = new UserDaoImpl();
@Override
public void registerUser(User user) {
if (userDao.find(user.getUserName())!=null) {
System.out.println("用户存在");
}
userDao.add(user);
}
@Override
public User loginUser(String userName, String userPwd) {
return userDao.find(userName, userPwd);
}
}
2.4.4 开发页面jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>用户注册</title>
</head>
<body style="text-align: center;">
<form action="${pageContext.request.contextPath}/register" method="post">
<table width="60%" border="1">
<tr>
<td>用户名</td>
<td><input type="text" name="userName" value="${registerBean.userName}">${registerBean.errors.userName}</td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="userPwd" value="${registerBean.userPwd}">${registerBean.errors.userPwd}</td>
</tr>
<tr>
<td>确认密码</td>
<td><input type="password" name="confirmPwd" value="${registerBean.confirmPwd}">${registerBean.errors.confirmPwd}
</td>
</tr>
<tr>
<td>邮箱</td>
<td><input type="text" name="email" value="${registerBean.email}">${registerBean.errors.email}
</td>
</tr>
<tr>
<td>生日</td>
<td><input type="text" name="birthday" value="${registerBean.birthday}">${registerBean.errors.birthday}</td>
</tr>
<tr>
<td><input type="reset" value="清空"></td>
<td><input type="submit" value="注册"></td>
</tr>
</table>
</form>
</body>
</html>
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>用户登陆</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login" method="post">
用户名:<input type="text" name="username"><br />
密码:<input type="password" name="password"><br />
<input type="submit" value="登陆">
</form>
</body>
</html>
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
${message}
</body>
</html>
<%@ page language="java" pageEncoding="UTF-8"%>
<%--为了避免在jsp页面中出现java代码,这里引入jstl标签库,利用jstl标签库提供的标签来做一些逻辑判断处理 --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<html>
<head>
<title>首页</title>
<script type="text/javascript">
function doLogout(){
//访问LogoutServlet注销当前登录的用户
window.location.href="${pageContext.request.contextPath}/logout";
}
</script>
</head>
<body>
<h1>Angelia的网站</h1>
<hr />
<c:if test="${user==null}">
<a href="${pageContext.request.contextPath}/registerIndex" target="_blank">注册</a>
<a href="${pageContext.request.contextPath}/loginIndex">登陆</a>
</c:if>
<c:if test="${user!=null}">
欢迎您:${user.userName}
<input type="button" value="退出登陆" onclick="doLogout()">
</c:if>
<hr />
</body>
</html>
2.4.5 开发bean层
public class RegisterBean {
private String userName;
private String userPwd;
private String confirmPwd;
private String email;
private String birthday;
/**
* 存储校验不通过时给用户的错误提示信息
*/
private Map<String, String> errors = new HashMap<String, String>();
public Map<String, String> getErrors() {
return errors;
}
public void setErrors(Map<String, String> errors) {
this.errors = errors;
}
/*
* validate方法负责校验表单输入项 表单输入项校验规则:
* userName; 用户名不能为空,并且要是4-10的字母 abcdABcd
* userPwd; 密码不能为空,并且要是3-8的数字
* confirmPwd; 两次密码要一致
* email; 可以为空,不为空要是一个合法的邮箱
* birthday; 可以为空,不为空时,要是一个合法的日期
*/
public boolean validate() {
boolean isOk = true;
if (this.userName == null || this.userName.trim().equals("")) {
isOk = false;
errors.put("userName", "用户名不能为空!!");
} else {
if (!this.userName.matches("[a-zA-Z]{4,10}")) {
isOk = false;
errors.put("userName", "用户名必须是4-10位的字母!!");
}
}
if (this.userPwd == null || this.userPwd.trim().equals("")) {
isOk = false;
errors.put("userPwd", "密码不能为空!!");
} else {
if (!this.userPwd.matches("\\d{3,8}")) {
isOk = false;
errors.put("userPwd", "密码必须是3-8位的数字!!");
}
}
// password2; 两次密码要一致
if (this.confirmPwd != null) {
if (!this.confirmPwd.equals(this.userPwd)) {
isOk = false;
errors.put("confirmPwd", "两次密码不一致!!");
}
}
// email可以为空,不为空要是一个合法的邮箱
if (this.email != null && !this.email.trim().equals("")) {
if (!this.email.matches("\\w+@\\w+(\\.\\w+)+")) {
isOk = false;
errors.put("email", "邮箱不是一个合法邮箱!!");
}
}
// birthday可以为空,不为空时,要是一个合法的日期
if (this.birthday != null && !this.birthday.trim().equals("")) {
try {
DateLocaleConverter conver = new DateLocaleConverter();
conver.convert(this.birthday);
} catch (Exception e) {
isOk = false;
errors.put("birthday", "生日必须要是一个日期!!");
}
}
return isOk;
}
get/set 省略
}
2.4.6 开发controller,以及配置文件web.xml
public class RegisterIndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 将客户端提交的表单数据封装到RegisterBean对象中
RegisterBean registerBean = WebUtils.request2Bean(request, RegisterBean.class);
// 校验用户注册填写的表单数据
if (registerBean.validate() == false) {// 如果校验失败
// 将封装了用户填写的表单数据的bean对象发送回register.jsp页面的form表单中进行显示
request.setAttribute("registerBean", registerBean);
// 校验失败就说明是用户填写的表单数据有问题,那么就跳转回register.jsp
request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response);
return;
}
User user = new User();
try {
// 注册字符串到日期的转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.copyProperties(registerBean, user);// 把表单的数据填充到JavaBean user中
IUserService service = new UserServiceImpl();
// 调用service层提供的注册用户服务实现用户注册
service.registerUser(user);
String message = String.format("注册成功!!3秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='3;url=%s'/>",
request.getContextPath() + "/loginIndex");
request.setAttribute("message", message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace(); // 在后台记录异常
request.setAttribute("message", "对不起,注册失败!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class LoginIndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取用户填写的登录用户名
String username = request.getParameter("username");
//获取用户填写的登录密码
String password = request.getParameter("password");
IUserService service = new UserServiceImpl();
//用户登录
User user = service.loginUser(username, password);
if(user==null){
String message = String.format("对不起,用户名或密码有误!!请重新登录!2秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='2;url=%s'",
request.getContextPath()+"/login");
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
//登录成功后,就将用户存储到session中
request.getSession().setAttribute("user", user);
String message = String.format("恭喜:%s,登陆成功!本页将在3秒后跳到首页!!<meta http-equiv='refresh' content='3;url=%s'",
user.getUserName(), request.getContextPath()+"/index.jsp");
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//移除存储在session中的user对象,实现注销功能
request.getSession().removeAttribute("user");
String message = String.format(
"注销成功!!3秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='3;url=%s'/>",
request.getContextPath()+"/loginIndex");
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>RegisterIndexServlet</servlet-name>
<servlet-class>angelia.mvc.controller.RegisterIndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterIndexServlet</servlet-name>
<url-pattern>/registerIndex</url-pattern>
</servlet-mapping>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>angelia.mvc.controller.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginIndexServlet</servlet-name>
<servlet-class>angelia.mvc.controller.LoginIndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginIndexServlet</servlet-name>
<url-pattern>/loginIndex</url-pattern>
</servlet-mapping>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>angelia.mvc.controller.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>angelia.mvc.controller.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/logout</url-pattern>
</servlet-mapping>
2.4.7 开发工具层util
public class MongdbUtil {
public static DBCollection getDBCollection(String name) {
System.out.println("连接Mongo");
try {
MongoClient mongo = new MongoClient(host, port);
System.out.println("连接Mongo成功");
return mongo.getDB("test").getCollection(name);// 有集合就返回,无就根据名字创建一个新的集合;
} catch (UnknownHostException e) {
System.out.println("连接Mongo失败");
}
return null;
}
}
public class WebUtils {
/**
* 将request对象转换成T对象
*
* @param request
* @param clazz
* @return
*/
public static <T> T request2Bean(HttpServletRequest request, Class<T> clazz) {
try {
T bean = clazz.newInstance();
Enumeration<String> e = request.getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
BeanUtils.setProperty(bean, name, request.getParameter(name));
}
return bean;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3 启动项目后访问http://localhost:8080/servlet-jsp-javabean/
4 编码web项目的国家化
4.1 编写资源文件resource_zh_CN.properties和resource_en_US.properties
website.title=Angelia的网站
language.zh=中文
language.en=英文
register=注册
login=登录
userRegister=用户注册
userName=用户名
userPwd=密码
confirmPwd=确认密码
email=邮箱
birthday=生日
reset=清空
logout=退出登陆
welcome=欢迎您
website.title=Web Site of Angelia
language.zh=ZH
language.en=EN
register=REGISTER
login=LOGIN
userRegister=User Register
userName=User Name
userPwd=Password
confirmPwd=Confirm Password
email=Email
birthday=Birthday
reset=RESET
logout=Logout
welcome=Welcome
4.2 编写资源文件读取工具类StringsUtil
public class StringsUtil {
public static ResourceBundle getResources(String language){
ResourceBundle bundle=ResourceBundle.getBundle("resource", Locale.getDefault());
if(language!=null){
if("zh".equals(language)){
bundle=ResourceBundle.getBundle("resource",Locale.CHINA);
}
else if("en".equals(language)){
bundle=ResourceBundle.getBundle("resource",Locale.US);
}
}
return bundle;
}
}
4.3 编写LanguageServlet类,根据获取语言language把资源文件放到session。且web.xml配置LanguageServlet。
public class LanguageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String language = request.getParameter("language");
request.getSession().setAttribute("language", language);
request.getSession().setAttribute("resources", StringsUtil.getResources(language));
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<servlet>
<servlet-name>LanguageServlet</servlet-name>
<servlet-class>angelia.mvc.controller.LanguageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LanguageServlet</servlet-name>
<url-pattern>/language</url-pattern>
</servlet-mapping>
4.4 修改index.jsp,及要国家化的页面
<body>
<h1>${resources.getString("website.title")}</h1>
<c:choose>
<c:when test="${language=='zh'}">
<a href="${pageContext.request.contextPath}/language?language=en">${resources.getString("language.en")}</a>
</c:when>
<c:otherwise>
<a href="${pageContext.request.contextPath}/language?language=zh">${resources.getString("language.zh")}</a>
</c:otherwise>
</c:choose>
<hr />
<c:if test="${user==null}">
<a href="${pageContext.request.contextPath}/registerIndex" target="_blank">${resources.register}</a>
<a href="${pageContext.request.contextPath}/loginIndex">${resources.login}</a>
</c:if>
<c:if test="${user!=null}">
${resources.getString("welcome")}:${user.userName}
<input type="button" value="${resources.getString('logout')}" onclick="doLogout()">
</c:if>
<hr />
</body>
5 由于访问语言的servlet后,资源文件才会被加载。所以这样实现,直接点注册或者登陆,会出现异常。这里利用Filter,在客户端访问任何连接时,首先检查资源问价是否在session中,如不在,把资源文件加载到session。
public class LanguageFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
if(req.getSession().getAttribute("resources")==null){
String language = Locale.getDefault().getLanguage();
req.getSession().setAttribute("language", language);
req.getSession().setAttribute("resources", StringsUtil.getResources(language));
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>LanguageFilter</filter-name>
<filter-class>angelia.mvc.filter.LanguageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LanguageFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5 启动项目后访问http://localhost:8080/servlet-jsp-javabean/