J2EE 电商实战相关知识点拾遗
一、实体类设计
所谓的实体类,就是对于数据库中的表的互相映射的类。
这是一种ORM的设计思想,即一个对象
,对应数据库里的一条记录
。
基于前面数据库表结构的分析和设计,根据创建表的SQL语句,和表与页面一一对应关系,按照表与表之间的依赖顺序,逐个设计我们项目的实体类。
包名
所有的实体类,都放在 shop/src/shop.bean 包中
toString()重写
在开发的时候,我们会用到重写这个方法:
public String toString() {
return "Category [name=" + name + "]";
}
表示重写toString方法,当打印Category对象的时候,会打印其名称。 在实际业务的时候并没有调用,在测试的过程中会调用到。
示例:
Category.java
package tmall.bean;
import java.util.List;
public class Category {
private String name;
private int id;
List<Product> products;
List<List<Product>> productsByRow;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Category [name=" + name + "]";
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public List<List<Product>> getProductsByRow() {
return productsByRow;
}
public void setProductsByRow(List<List<Product>> productsByRow) {
this.productsByRow = productsByRow;
}
}
二、DAO类设计
接下来是DAO类,DAO是Data Access Object的缩写,这些类专门用于进行数据库访问的操作。
-
首先讲解两个工具类,
DBUtil
和DateUtil
,因为在DAO类中会用到这两个工具类 -
接着按照依赖顺序,逐个讲解不同的DAO类以及其中的方法
步骤1:DBUtil
DBUtil:数据库工具类,这个类的作用是初始化驱动,并且提供一个getConnection用于获取连接。 在后续的所有DAO中,当需要获取连接的时候,都采用这种方式进行。
数据库连接的参数,如数据库名称,账号密码,编码方式等都设计在属性上,便于统一修改,降低维护成本。
package tmall.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
static String ip = "127.0.0.1";
static int port = 3306;
static String database = "tmall";
static String encoding = "UTF-8";
static String loginName = "root";
static String password = "admin";
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
return DriverManager.getConnection(url, loginName, password);
}
public static void main(String[] args) throws SQLException {
System.out.println(getConnection());
}
}
步骤2:DateUtil
DateUtil这个日期工具类主要是用于java.util.Date类与java.sql.Timestamp 类的互相转换。
因为在实体类中日期类型的属性,使用的都是java.util.Date类。
而为了在MySQL中的日期格式里保存时间信息,必须使用datetime类型的字段,而jdbc要获取datetime类型字段的信息,需要采用java.sql.Timestamp来获取,否则只会保留日期信息,而丢失时间信息。
package tmall.util;
public class DateUtil {
public static java.sql.Timestamp d2t(java.util.Date d) {
if (null == d)
return null;
return new java.sql.Timestamp(d.getTime());
}
public static java.util.Date t2d(java.sql.Timestamp t) {
if (null == t)
return null;
return new java.util.Date(t.getTime());
}
}
三、导入jar包
项目中需要引入第三方 jar包,以后我们使用maven,现在先手动导入:
四、Filter配合Servlet
Servlet生命周期
一个Servlet的生命周期由 实例化,初始化,提供服务,销毁,被回收
几个步骤组成。
实例化
用户通过浏览器输入一个路径,这个路径对应的servlet被调用的时候,该Servlet就会被实例化
为LoginServlet显式提供一个构造方法 LoginServlet()
无论访问了多少次LoginServlet
LoginServlet构造方法 只会执行一次,所以Servlet是单实例的。
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
public LoginServlet(){
System.out.println("LoginServlet 构造方法 被调用");
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//略
}
}
初始化
LoginServlet 继承了HttpServlet,同时也继承了init(ServletConfig) 方法
init 方法是一个实例方法,所以会在构造方法执行后执行。
无论访问了多少次LoginSerlvet
init初始化 只会执行一次
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
public LoginServlet() {
System.out.println("LoginServlet 构造方法 被调用");
}
public void init(ServletConfig config) {
System.out.println("init(ServletConfig)");
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 略
}
}
提供服务
接下来就是执行service()方法,然后通过浏览器传递过来的信息进行判断,是调用doGet()还是doPost()方法
在service()中就会编写我们的业务代码
,在本例中就是判断用户输入的账号和密码是否正确
public class LoginServlet extends HttpServlet {
public LoginServlet() {
System.out.println("LoginServlet 构造方法 被调用");
}
public void init(ServletConfig config) {
System.out.println("init(ServletConfig)");
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String password = request.getParameter("password");
String html = null;
if ("admin".equals(name) && "123".equals(password))
html = "<div style='color:green'>success</div>";
else
html = "<div style='color:red'>fail</div>";
PrintWriter pw = response.getWriter();
pw.println(html);
}
}
销毁
接着是销毁destroy()
在如下几种情况下,会调用destroy()
- 该Servlet所在的web应用重新启动
在server.xml中配置该web应用的时候用到了<Context path="/" docBase="e:\\project\\j2ee\\web" debug="0" reloadable="false" />
如果把 reloadable="false" 改为reloadable="true" 就表示有任何类发生的更新,web应用会自动重启
当web应用自动重启的时候,destroy()方法就会被调用
- 关闭tomcat的时候 destroy()方法会被调用,但是这个一般都发生的很快,不易被发现。
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
public void destroy() {
System.out.println("destroy()");
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 略
}
}
被回收
当该Servlet被销毁后,就满足垃圾回收的条件了。 当下一次垃圾回收GC来临的时候,就有可能被回收。这个也是不容易被观察到的现象。
Servlet service()
LoginServlet继承了HttpServlet,同时也继承了一个方法
service(HttpServletRequest , HttpServletResponse )
实际上,在执行doGet()或者doPost()之前,都会先执行service()
由service()方法进行判断,到底该调用doGet()还是doPost()
可以发现,service(), doGet(), doPost() 三种方式的参数列表都是一样的。
所以,有时候也会直接重写service()方法,在其中提供相应的服务,就不用区分到底是get还是post了。
比如把前面的登录的LoginServlet,改为提供service方法,也可以达到相同的效果
...
public class LoginServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String password = request.getParameter("password");
String html = null;
if ("admin".equals(name) && "123".equals(password))
html = "<div style='color:green'>success</div>";
else
html = "<div style='color:red'>fail</div>";
PrintWriter pw = response.getWriter();
pw.println(html);
}
}
Servlet 跳转
页面跳转是开发一个web应用经常会发生的事情。比如登录成功或是失败后,分别会跳转到不同的页面。跳转的方式有两种,服务端跳转
和客户端跳转
。
服务端跳转
在Servlet中进行服务端跳转的方式:
request.getRequestDispatcher("success.html").forward(request, response);
服务端跳转可以看到浏览器的地址依然是/login
路径,并不会变成success.html
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String password = request.getParameter("password");
if ("admin".equals(name) && "123".equals(password)) {
request.getRequestDispatcher("success.html").forward(request, response);
}
}
}
客户端跳转
在Servlet中进行客户端跳转的方式:
response.sendRedirect("fail.html");
可以观察到,浏览器地址发生了变化,变为 127.0.0.1/fail.html
示意图
Filter使用
Filter就像一个一个哨卡,用户的请求需要经过Filter,并且可以有多个过滤器。
编写测试 Filter
开发一个简单的FirstFilter,用来打印用户访问ip地址和访问的页面
HttpServletRequest request = (HttpServletRequest) req;
doFilter()
方法中的req参数的类型是ServletRequest,需要转换为HttpServletRequest类型方便调用某些方法 (参考request常见方法)
String ip = request.getRemoteAddr();
获取来路用户的ip地址
String url = request.getRequestURL().toString();
获取用户访问的页面地址
System.out.printf("%s %s 访问了 %s%n", date, ip, url);
在控制台打印出来
chain.doFilter(request, response);
过滤器放行
,表示继续运行下一个过滤器,或者最终访问的某个servlet,jsp,html等等
package filter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FirstFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String ip = request.getRemoteAddr();
String url = request.getRequestURL().toString();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = new Date();
String date = sdf.format(d);
System.out.printf("%s %s 访问了 %s%n", date, ip, url);
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
配置web.xml
在web.xml中进行filter的配置,和servlet的配置很类似
<url-pattern>/*</url-pattern>
表示所有的访问都会过滤
如果配置成
<url-pattern>*.jsp</url-pattern>
就表示只过滤jsp
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)