Java Web的编写

章节索引

  • 前提
  • IDE的选择
  • NetBeans的安装
  • 创建并配置项目
    • 1.新建项目
    • 2.编写前的配置
    • 3.导入外部包
    • 4.创建包
  • 开始撸码!
    • 1.DBManager
    • 2.User
    • 3.UserDAO
    • 4.LoginServlet
    • 点击下一步,不要点完成!!!
  • 后记


前提

索引文章 中我提到过,我们用Java Web来写服务器程序,这篇文章我们真正的进入到编码的环节。


IDE的选择

市面上能编写Java Web项目的IDE应该说数不胜数了,但是最主流的IDE当属Eclipse——在Android Studio发布后被Google放弃支持的IDE。之所以最主流,是因为它具有体积小…这一个优点。

因为用它编写代码的时候很多事情都需要手动来做,因此我选择了一个“非主流”的IDE——NetBeans


NetBeans的安装

本来这里我想一句话带过的,但是发现有两个步骤必须说一下:

1.下载按钮在主页右边,如果没看到,你可能会点上面导航栏的“NetBeans IDE”,在看到一堆介绍之后不知所措;

Java Web的编写_第1张图片

2.下载页面为我们提供了多个版本,我们选择第二个,带有Java EE的版本(至于Java EE是什么,自己查吧,不懂也没关系,你知道这个版本能写Java Web服务器程序就行了)。

Java Web的编写_第2张图片

下载下来之后的安装我就不赘述了。


创建并配置项目

1.新建项目

打开IDE,文件->新建项目

Java Web的编写_第3张图片

在弹出的窗口中,左边选择Java Web,右边选择Web应用程序,点击下一步

Java Web的编写_第4张图片

在这一步中,输入你的项目名称,选择项目位置(可以和我一样,建一个WorkSpace 文件夹),点击下一步

Java Web的编写_第5张图片

在这一步中,默认设置应该和下图一样,否则你需要添加一下服务器,然后点击下一步

Java Web的编写_第6张图片

在这一步中,我们任何框架都不用(那些都是优化用的,我们先把基础的流程跑通),然后点击完成

Java Web的编写_第7张图片

2.编写前的配置

新建项目完成后,右边应该会自动打开默认的index.jsp,我们不需要它,那是写网站用的默认页面,因此点右上角的“X”关闭。

Java Web的编写_第8张图片

现在我们来给自己的项目添加配置文件(不清楚为什么新建项目的时候不直接生成)

选中我们的项目,然后右键,在弹出菜单里选择新建->标准部署描述符(web.xml)

Java Web的编写_第9张图片

在弹出的窗口中我们点击完成(因为都是默认的不能更改)

Java Web的编写_第10张图片

之后我们会看见左边自动打开了配置文件目录,里面有一个web.xml文件,右边自动打开了这个文件,可以看到里面的内容

Java Web的编写_第11张图片

3.导入外部包

这是相当重要的一步,如果不做,编程的时候会报各种找不到类、找不到文件的错误。

我们要用到的是下面的8个 .JAR 文件

Java Web的编写_第12张图片

前6个是JSONObject包, 是一个集合,6个在同一个压缩包里,去以下地址下载,
链接 密码:pa10

第7个是MySQL的驱动包, 去以下地址下载
链接 密码:je2o

第8个是Servlet API包, 去以下地址下载
链接 密码:6s1t

ok,下载完这些包,我们在项目路径下建立一个lib文件夹,把刚刚下载到的8个 .JAR文件放进去

Java Web的编写_第13张图片

这还不算完,我们还需要去项目里把他们引进去。
右键点击库->添加JAR/文件夹

Java Web的编写_第14张图片

在弹出的窗口中,找到lib文件夹,选中所有的JAR文件,然后再右边选择相对路径,最后点击打开

Java Web的编写_第15张图片

完成之后,我们点击库文件夹,可以看到,所有的外部依赖包都已导入库中

Java Web的编写_第16张图片

4.创建包

点开源包我们可以看见,里面有一个灰色的默认包,不推荐使用默认包,我们建立自己的包。右键源包->新建->Java 包

Java Web的编写_第17张图片

在弹出的窗口中,修改包名,不一定要像我这样,但是格式一般是:net/com . [公司名] . 组名 . 应用名

Java Web的编写_第18张图片

此时,我们看到源包中的默认包消失,换成了我们刚刚创建的包,灰色是因为它是空的,一会儿创建个类进去就变成正常的颜色了。

Java Web的编写_第19张图片


开始撸码!

为了方便说明,我们以写一个用户登录的功能为目标来讲。
要实现用户登录,我们需要写四个类, 下面我会分别讲解。

1.DBManager

这是一个数据库连接管理类,负责数据库连接的创建、管理和销毁。这个类可以说在任何项目中都是是通用的,直接新建一个类把代码复制进去就行,下面贴出代码:

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>
    ......

2.User

用户类,这种类一般叫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;
    }
}

3.UserDAO

这个类我需要重点讲一下,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型,即数据库中受到更新操作影响的行数。

4.LoginServlet

这个类是我们的重中之重,它就是处理来自客户端的请求,并发回响应的类。

①创建Servlet
它的创建和前三个类不一样, 看图↓

Java Web的编写_第20张图片

②更改Servlet名字
在弹出的界面修改Servlet名字,然后

点击下一步,不要点完成!!!

Java Web的编写_第21张图片

③配置Servlet部署
上一步如果点了完成会跳过这一步,然后需要手动部署,如果忘了部署,你的请求得不到响应,你连错误都找不到!
选中 将信息添加到部署描述符(web.xml) 复选框,然后点完成。

Java Web的编写_第22张图片

这时打开web.xml,你会看见它里面新增了这些东西

Java Web的编写_第23张图片

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的路径下,以下是步骤

①打包
右键点击我们的项目->清理并构建

Java Web的编写_第24张图片

②部署
去WorkSpace中找到这个项目生成的 .WAR 文件,然后复制到Tomcat的指定目录下去,见下面两张图↓

Java Web的编写_第25张图片

Tomcat Web应用文件夹

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

你可能感兴趣的:(Java后端实战记录)