最佳实践:Servlet处理逻辑,把结果封装到域对象中(ServletRequest、HttpSession、ServletContext),转发给JSP,让JSP只负责显示。
数据的封装要用到JavaBean。架构思路如下:
降低了各层之间的依赖,方便后期扩展与维护
(1)javabean开始 com.fengyuwuzu.domain
封装数据,名词:用户
(2)业务接口com.fengyuwuzu.service
BusinessService:
void regist(User user) throws UserExistException;
User login(String username,String password);
(3)DAO接口com.fengyuwuzu.dao
void save(User user);
User findUser(String username);
User findUser(String username,String password);
(4)DAO实现com.fengyuwuzu.dao.impl
public class UserDaoMySQLImpl implements UserDao
(5)业务实现com.fengyuwuzu.service.impl
public class BusinessServiceImpl implements BusinessService
(6)单元测试com.fengyuwuzu.test
(7)表现层:com.fengyuwuzu.web.controller
html+jsp+servlet。LoginServlet+LogoutServlet+RegistServlet
(8)工具类com.fengyuwuzu.util
JdbcUtil、FillBeanUtil
首先我们根据目的,来创建javabean,我们希望实现登入和注册,那么现在我们针对是用户注册信息。
public class User implements Serializable {
private String username;
private String password;
private String email;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}。。。
use day15;
create table user(
username varchar(100) primary key,
password varchar(100) not null,
email varchar(100) not null,
birthday date
);
有了javabean我们操作的对象也就明确了,这个时候我们要明确我们要做什么,现在我们要注册和登入,所以在业务逻辑层,我们要实现的是注册和登入函数。这里只是根据要设计的功能,写出接口函数。
//根据需求来定
//接口:把注释写的没有歧义
public interface BusinessService {
/**
* 用户注册
* @param user 注册信息
* @throws UserExistException 如果注册用户名已经存在了,抛出此异常
*/
void regist(User user) throws UserExistException;
/**
* 完成用户登录
* @param username 用户名
* @param password 密码
* @return 如果用户名或密码错误,要返回null
*/
User login(String username,String password);
}
我们明确了业务要实现的几个功能,而这些功能依赖于持久层的数据,我们要明确持久层的操作,即数据的保存和查找:
//不负责业务逻辑,只负责CRUD
public interface UserDao {
/**
* 保存用户信息
* @param user
*/
void save(User user);
/**
* 根据用户名查询用户
* @param username
* @return 如果不存在返回null
*/
User findUser(String username);
/**
* 根据用户名和密码查询用户
* @param username
* @param password
* @return 如果不存在返回null
*/
User findUser(String username,String password);
}
明确了底层要进行数据的保存和查找,那么现在我们可以实现DAO层的具体实现,这样我就可以接着实现业务逻辑层的实现了。
DAO的实现就是:连接数据库,进行数据库的CRUD
public class UserDaoMySQLImpl implements UserDao {
public void save(User user) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate("insert into user (username,password,email,birthday) values ('"+user.getUsername()+"','"+user.getPassword()+"','"+user.getEmail()+"','"+user.getBirthday().toLocaleString()+"')");
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}
public User findUser(String username) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from user where username='"+username+"'");
if(rs.next()){
User user = new User();
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
return user;
}else{
return null;
}
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}
public User findUser(String username, String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from user where username='"+username+"' and password='"+password+"'");
if(rs.next()){
User user = new User();
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
return user;
}else{
return null;
}
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}
}
我们实现了DAO接口,并具体实现了DAO操作的实现,那我们业务逻辑的实现就可以利用DAO的实现来操作数据库的内容了。
业务实现,是为servlet服务的,这样servlet就可以调用这里实现的方法操作到底层的数据了。
public class BusinessServiceImpl implements BusinessService {
private UserDao dao = BeanFactory.getUserDao();
public void regist(User user) throws UserExistException {
if(user==null)
throw new IllegalArgumentException("The param user can not be null");
User dbUser = dao.findUser(user.getUsername());
if(dbUser!=null){
throw new UserExistException("The username \""+user.getUsername()+"\"用户已经存在");
}
dao.save(user);
}
public User login(String username, String password) {
return dao.findUser(username, password);
}
}
之上我们实现了业务逻辑和DAO层的东西,那么现在我们可以进行单元测试,测试业务逻辑层对数据库的操作是否都是正常的,一旦测试通过,证明我们业务逻辑都已经完全打通,可以交给表现层调用了
用户点击-->触发 servlet被调用-->servlet里面创建业务逻辑的实例,来调用里面的方法-->持久层数据被操作。
(1)首页jsp:
XX网站
注册
登录
欢迎您:${sessionScope.user.username}
注销
(3)登入jsp
(4)RegistServlet
//编码重点。完成注册
public class RegistServlet extends HttpServlet {
private BusinessService s = new BusinessServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
//获取表单数据,封装到JavaBean中。引入FormBean:特点属性和表单字段完全一致。且都是String类型。封装错误消息。
UserFormBean formBean = FillBeanUtil.fillBean(request, UserFormBean.class);
//数据验证:服务器端验证。实际开发中:客户端+服务器端验证。
if(!formBean.validate()){
//不通过:回显数据,消息提示
request.setAttribute("formBean", formBean);
request.getRequestDispatcher("/regist.jsp").forward(request, response);
return;
}
//填充模型:formBean---->JavaBean
User user = new User();
// user.setUsername(formBean.getUsername());
// user.setPassword(formBean.getPassword());
// user.setEmail(formBean.getEmail());
// DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// try {
// user.setBirthday(df.parse(formBean.getBirthday()));
// } catch (ParseException e) {
// e.printStackTrace();
// }
ConvertUtils.register(new DateLocaleConverter(), Date.class);//注册类型转换器
try {
BeanUtils.copyProperties(user, formBean);
} catch (Exception e) {
e.printStackTrace();
}
//通过:调用Service保存数据
try {
s.regist(user);
response.getWriter().write("保存成功!2秒后转向主页");
response.setHeader("Refresh", "2;URL="+request.getContextPath());
} catch (UserExistException e) {
//数据回显和提示
formBean.getErrors().put("username", "用户名已经存在了");
request.setAttribute("formBean", formBean);
request.getRequestDispatcher("/regist.jsp").forward(request, response);
return;
}
}
(5)LoginServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = s.login(username, password);
if(user==null){
//错误的用户名或密码
response.getWriter().write("错误的用户名或密码。2秒后转向登录页面。");
response.setHeader("Refresh", "2;URL="+request.getContextPath()+"/login.jsp");
return;
}
//登录成功
request.getSession().setAttribute("user", user);
response.getWriter().write("登录成功。2秒后转向主页。");
response.setHeader("Refresh", "2;URL="+request.getContextPath());
}
(6)LogoutServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
request.getSession().removeAttribute("user");
// request.getSession().invalidate();
response.getWriter().write("注销成功。2秒后转向主页。");
response.setHeader("Refresh", "2;URL="+request.getContextPath());
}
8、工具类
为了简化代码,避免重复性的代码,将常用的代码抽取出来。如数据库操作,javabean填充等
(1)JdbcUtil
//与具体的数据库解耦
public class JdbcUtil {
private static String driverClass;
private static String url;
private static String user;
private static String password;
static{
try {
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dbcfg.properties");
Properties props = new Properties();
props.load(in);
driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
Class.forName(driverClass);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws Exception {
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
public static void release(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
依赖于:
commons-beanutils-1.8.3.jar
commons-logging-1.1.1.jar
public class FillBeanUtil {
public static T fillBean(HttpServletRequest request,Class clazz){
try {
T bean = clazz.newInstance();
BeanUtils.populate(bean, request.getParameterMap());
return bean;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class BeanFactory {
private static String userDao;
static{
try {
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dao.properties");
Properties props = new Properties();
props.load(in);
userDao = props.getProperty("userDao");
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static UserDao getUserDao(){
try {
return (UserDao) Class.forName(userDao).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
http://download.csdn.net/detail/fengyuwuzu0519/9899979