在 索引文章 中我提到过,我们用Java Web来写服务器程序,这篇文章我们真正的进入到编码的环节。
市面上能编写Java Web项目的IDE应该说数不胜数了,但是最主流的IDE当属Eclipse——在Android Studio发布后被Google放弃支持的IDE。之所以最主流,是因为它具有体积小…这一个优点。
因为用它编写代码的时候很多事情都需要手动来做,因此我选择了一个“非主流”的IDE——NetBeans
本来这里我想一句话带过的,但是发现有两个步骤必须说一下:
1.下载按钮在主页右边,如果没看到,你可能会点上面导航栏的“NetBeans IDE”,在看到一堆介绍之后不知所措;
2.下载页面为我们提供了多个版本,我们选择第二个,带有Java EE的版本(至于Java EE是什么,自己查吧,不懂也没关系,你知道这个版本能写Java Web服务器程序就行了)。
下载下来之后的安装我就不赘述了。
打开IDE,文件->新建项目
在弹出的窗口中,左边选择Java Web,右边选择Web应用程序,点击下一步
在这一步中,输入你的项目名称,选择项目位置(可以和我一样,建一个WorkSpace 文件夹),点击下一步
在这一步中,默认设置应该和下图一样,否则你需要添加一下服务器,然后点击下一步
在这一步中,我们任何框架都不用(那些都是优化用的,我们先把基础的流程跑通),然后点击完成
新建项目完成后,右边应该会自动打开默认的index.jsp,我们不需要它,那是写网站用的默认页面,因此点右上角的“X”关闭。
现在我们来给自己的项目添加配置文件(不清楚为什么新建项目的时候不直接生成)
选中我们的项目,然后右键,在弹出菜单里选择新建->标准部署描述符(web.xml)
在弹出的窗口中我们点击完成(因为都是默认的不能更改)
之后我们会看见左边自动打开了配置文件目录,里面有一个web.xml文件,右边自动打开了这个文件,可以看到里面的内容
这是相当重要的一步,如果不做,编程的时候会报各种找不到类、找不到文件的错误。
我们要用到的是下面的8个 .JAR 文件
前6个是JSONObject包, 是一个集合,6个在同一个压缩包里,去以下地址下载,
链接 密码:pa10
第7个是MySQL的驱动包, 去以下地址下载
链接 密码:je2o
第8个是Servlet API包, 去以下地址下载
链接 密码:6s1t
ok,下载完这些包,我们在项目路径下建立一个lib文件夹,把刚刚下载到的8个 .JAR文件放进去
这还不算完,我们还需要去项目里把他们引进去。
右键点击库->添加JAR/文件夹
在弹出的窗口中,找到lib文件夹,选中所有的JAR文件,然后再右边选择相对路径,最后点击打开
完成之后,我们点击库文件夹,可以看到,所有的外部依赖包都已导入库中
点开源包我们可以看见,里面有一个灰色的默认包,不推荐使用默认包,我们建立自己的包。右键源包->新建->Java 包
在弹出的窗口中,修改包名,不一定要像我这样,但是格式一般是:net/com . [公司名] . 组名 . 应用名
此时,我们看到源包中的默认包消失,换成了我们刚刚创建的包,灰色是因为它是空的,一会儿创建个类进去就变成正常的颜色了。
为了方便说明,我们以写一个用户登录的功能为目标来讲。
要实现用户登录,我们需要写四个类, 下面我会分别讲解。
这是一个数据库连接管理类,负责数据库连接的创建、管理和销毁。这个类可以说在任何项目中都是是通用的,直接新建一个类把代码复制进去就行,下面贴出代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
/**
* 数据库管理类,提供连接数据库和拆解链接功能
*
* @author Implementist
*/
public class DBManager extends HttpServlet {
ServletConfig config; //定义一个ServletConfig对象
private static String username; //定义的数据库用户名
private static String password; //定义的数据库连接密码
private static String url; //定义数据库连接URL
private static Connection connection; //定义连接
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); //继承父类的init()方法
this.config = config; //获取配置信息
username = config.getInitParameter("DBUsername"); //获取数据库用户名
password = config.getInitParameter("DBPassword"); //获取数据库连接密码
url = config.getInitParameter("ConnectionURL"); //获取数据库连接URL
}
/**
* 获得数据库连接对象
*
* @return 数据库连接对象
*/
public static Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | SQLException ex) {
Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
}
return connection;
}
/**
* 关闭所有的数据库连接资源
*
* @param connection Connection 链接
* @param statement Statement 资源
* @param resultSet ResultSet 结果集合
*/
public static void closeAll(Connection connection, Statement statement,
ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException ex) {
Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
上面调用到config.getInitParameter函数的三行我需要解释一下:这里是从web.xml配置文件中读取初始化参数,我们需要做的是给DBManager这个Servlet添加三个初始化参数,即init-param,修改后web.xml中DBManager部分的内容形如:
......
<servlet>
<servlet-name>DBManagerservlet-name>
<servlet-class>包名.DBManagerservlet-class>
<init-param>
<param-name>DBUsernameparam-name>
<param-value>rootparam-value>
init-param>
<init-param>
<param-name>DBPasswordparam-name>
<param-value>param-value>
init-param>
<init-param>
<param-name>ConnectionURLparam-name>
<param-value>jdbc:mysql://localhost:3306/myfirstapp?characterEncoding=utf8param-value>
init-param>
<load-on-startup>0load-on-startup>
servlet>
......
用户类,这种类一般叫Java Bean,就是定义用户的各种字段,然后封装好就行了,下面贴出代码:
public class User {
//用户姓名
private String userName;
//用户密码
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
这个类我需要重点讲一下,DAO的意思是数据访问对象(Data Access Object),可以理解为对数据库中User表进行增删改查用的类,我只写一个查询函数,其他函数类推即可,下面贴出代码:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Administrator
*/
public class UserDAO {
/**
* 查询给定用户名的用户的详细信息
*
* @param userName 给定的用户名
* @return 查询到的封装了详细信息的User对象
*/
public static User queryUser(String userName) {
//获得数据库的连接对象
Connection connection = DBManager.getConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//生成SQL代码
StringBuilder sqlStatement = new StringBuilder();
sqlStatement.append("SELECT * FROM user WHERE UserName=?");
//设置数据库的字段值
try {
preparedStatement = connection.prepareStatement(sqlStatement.toString());
preparedStatement.setString(1, userName);
resultSet = preparedStatement.executeQuery();
User user = new User();
if (resultSet.next()) {
user.setUserName(resultSet.getString("UserName"));
user.setPassword(resultSet.getString("Password"));
return user;
} else {
return null;
}
} catch (SQLException ex) {
Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
return null;
} finally {
DBManager.closeAll(connection, preparedStatement, resultSet);
}
}
}
注意下面两行代码,这种形式的传值是为了避免传统的拼字符串方式造成的SQL注入攻击。
sqlStatement.append("SELECT * FROM user WHERE UserName=?");
preparedStatement.setInt(1, userName);
再举个类子,在写插入User的函数时,这里就写成下面几行这样:
sqlStatement.append("INSERT INTO user(UserName,Password) VALUES(?,?)");
preparedStatement.setString(1, user.getUserName());
preparedStatement.setString(2, user.getPassword());
这样就能明白这种形式的用法了。
另外,一个必须注意的地方是,除查询函数用executeQuery外,其他的增删改等操作都属于更新操作,要用executeUpdate,返回值为int型,即数据库中受到更新操作影响的行数。
这个类是我们的重中之重,它就是处理来自客户端的请求,并发回响应的类。
①创建Servlet
它的创建和前三个类不一样, 看图↓
②更改Servlet名字
在弹出的界面修改Servlet名字,然后
③配置Servlet部署
上一步如果点了完成会跳过这一步,然后需要手动部署,如果忘了部署,你的请求得不到响应,你连错误都找不到!
选中 将信息添加到部署描述符(web.xml) 复选框,然后点完成。
这时打开web.xml,你会看见它里面新增了这些东西
ok,回到LoginServlet中,验证请求中的账户密码是否正确,然后返回验证结果作为响应,下面给出代码
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
/**
* 测试登录Servlet
*
* @author Implementist
*/
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
try (PrintWriter out = response.getWriter()) {
//获得请求中传来的用户名和密码
String accountNumber = request.getParameter("AccountNumber").trim();
String password = request.getParameter("Password").trim();
//密码验证结果
Boolean verifyResult = verifyLogin(accountNumber, password);
Map<String, String> params = new HashMap<>();
JSONObject jsonObject = new JSONObject();
if (verifyResult) {
params.put("Result", "success");
} else {
params.put("Result", "failed");
}
jsonObject.put("params", params);
out.write(jsonObject.toString());
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
/**
* 验证用户名密码是否正确
*
* @param userName
* @param password
*/
private Boolean verifyLogin(String userName, String password) {
User user = UserDAO.queryUser(userName);
//账户密码验证
return null != user && password.equals(user.getPassword());
}
}
ok,写完这些,服务器端的登录功能请求响应就实现了,记得按Ctrl+S保存,不过这还不算完,我们需要把这个项目打包一下,然后放在Tomcat的路径下,以下是步骤
①打包
右键点击我们的项目->清理并构建
②部署
去WorkSpace中找到这个项目生成的 .WAR 文件,然后复制到Tomcat的指定目录下去,见下面两张图↓
ok,完事!
1.今天写着写着我突然想到,可能JSONObject还需要写一篇单独的博文来讲,但是直接照猫画虎应该也不会出啥问题,闲了再说;
2.每次修改完程序,记得保存->清理并构建->部署,然后在XAMPP控制面板中关闭再重启Tomcat,就能生效了。
3.今天终于写完了,这篇帖子写了好几天,好像也比较长,诸君就这么看吧。
4. 汉字乱码问题是客户端/服务器端通信、数据库存取时最常见的问题,今天想到这篇帖子的DBManager类的url变量后面加上?characterEncoding=utf8这个参数可以解决数据库存储汉字时的乱码问题,已经并注释一起加在上面的代码里了,供诸君参考。
——2018.01.30
5.之前一直困惑于必须在代码里写上数据库用户名和密码的问题,比较后知后觉,最近终于学到把它们写到配置文件里面然后动态读取的方法,已经修改了这部分的代码。
——2018.03.11
6.就说最近为什么关于Java Web这的问题变多了,刚刚突然发现,我上面给的8个jar包的下载链接都开始收费了,一个比一个黑。你们自己凑的jar包可能不兼容或者是错的,因此会有各种错误。各位稍安勿躁,今天晚些时候我会把自己的jar包上传到云盘上,然后把链接改过来。
——2018.03.14