jsp实现前后端交互

jsp实现前后端交互

编辑器:Idea 2020.2.3 notepad++

图形编辑器:mspaint

1 JSP技术概述

JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。

它实现了Html语法中的java扩张(以 <%, %>形式)。JSP与Servlet一样,是在服务器端执行的。通常返回给客户端的就是一个HTML文本,因此客户端只要有浏览器就能浏览。

为了能够使用java作为后端并通过servlet实现前后端通信,不妨将所有html改成jsp,jsp中实现表单创建,并上传至后端指定类,后端对数据库进行某些操作是的最终实现前端和数据库的交互。

2 servlet方面

2.1 整体功能

在前端实现表单创建和发送请求,tomcat服务器接收到请求后,使用重写后的doGet(request,response)方法对发送过来的请求进行处理,由于实现的是登录功能,故而在处理前端请求时需要访问数据库。

在serlet重写过程中需要重写doGet()方法,故而新建Login类继承HttpServlet类,进而改写所需方法。

2.2 tomcat配置

如果想要使用前后端交互功能,那么需要使用服务器,这里选用的是tomcat服务器。将前端请求发送至tomcat服务器后,根据设定将请求转至相应的后端程序。

2.2.1 下载与安装

关于tomcat配置,首先就是需要下载tomcat服务器。这个很简单,直接去官网,速度还行。

tomcat官方网址:https://tomcat.apache.org/download-90.cgi

如果下载的是zip,就是免安装版的,直接解压到喜欢的路径即可。我的路径是D:\jarfile\

2.2.2 项目结构配置

安装完成后就是相应的项目配置了。首先需要做的就是将项目转为web项目。点击F4,进入项目结构界面。

项目配置-1

点击加号后在下拉箭头选择web。这样会在原来的项目根目录下生成一个web目录,可以在这个目录下书写相关的jsp文件。

ps:其实,除了本身功能,jsp文件的书写和html文件的书写没有什么本质区别,只是jsp文件可以用java语言书写部分代码实现更多功能。故而可以把web作为html的根目录,在里面进行网页编写,但是网页后缀需要改成jsp。上图中也有我的项目结构,仅做参考。

其次就是对项目文件标记的说明。如果想要将某些文件夹作为某些用途,需要对此文件夹进行标记。例如,src是源码文件夹,此文件夹需要创建的是classinterfaceenum,但是倘若在没有标记的情况下,编辑器并不会知道这是什么用途的文件夹。就可能会发生无法进行新建java类的问题。按照下图标记

项目配置-2

src标记为sourcesout标记为Excluded(out是输出文件夹,相当于代码回收场,是一次编译后的结果,再次编译项目是创建的索引不会包含out的),其余的标记可以自行百度,这里不做额外补充

项目配置-3

点击Dependencies再点击加号建立相关的jar包依赖。点击加号之后会弹出一个下拉菜单,选择里面的library,光标置于library上时就会有另一个下拉菜单,选择里面的java,进而去选择路径,此时的路径就是2.2.1步骤你解压的tomcat路径,这样就把tomcat的依赖添加进来啦。至于mysql jar包的导入,就按照咱们最原始的jar包导入就好啦。我存放项目jar包的路径是项目路径下的lib,然后再“add as library"就可以啦。

ps:add as library,文件夹右键,里面就有,慢慢找不要慌。

2.2.3 Debug配置

这个时候基本配置就已经完成了,但是还是不能运行的。因为还没有对Debug就行配置

Debug配置-1

Debug配置-2

选择tomcat server的时候其实选择一个就够了,我选择的是local,之后就是弹出来一个命名,根据自己口味酌情命名。

Debug配置-3

点击F4,进入project structure,选择artifacts,然后如图选择就行,顺序是+->web application->from module,再点击以此确定就好了。

截至目前为止,整个项目的配置就完成啦!

2.2.4 web文件夹配置

废话不多说,在解释之前,先贴上源码(解释在源码中了/呲牙/呲牙/呲牙)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 欢迎文件,在项目运行时弹出的第一个界面 -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <!-- 在服务器上运行的小程序设定 -->
    <!-- 一个servlet对应一个servlet-mapping -->
    <servlet>
        <servlet-name>Login</servlet-name>
        <!-- 小程序对应后端路径 -->
        <!-- 这里指的是相对路径,src下的com.servlet.login.Login -->
        <!-- Login即为我的实现登录的后端类 -->
        <servlet-class>com.servlet.login.Login</servlet-class>
    </servlet>
    <!-- 小程序映射路径 -->
    <servlet-mapping>
        <servlet-name>Login</servlet-name>
        <!-- 这个是编译运行时小程序对应的输出路径,位于out中 -->
        <url-pattern>/servlet/login</url-pattern>
    </servlet-mapping>
    
    <!-- 与上同 -->
    <servlet>
        <servlet-name>Register</servlet-name>
        <servlet-class>com.servlet.register.Register</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Register</servlet-name>
        <url-pattern>/servlet/register</url-pattern>
    </servlet-mapping>
</web-app>

如果没有解释清楚的话,可以对照我的项目树状图理解这一部分。

2.3 Login

Account.jsp文件中调用了Login方法,作为登录表单请求的方法。当用户在网页上尝试登录时,请求的表单就会发送至后端,后端就收请求的类是LoginLoginHttpServlet的子类,通过改写HttpServlet中的doGet方法,相应前端请求,根据不同的响应结果实现不同的页面跳转。

package com.servlet.login;

import java.io.*;

import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mysql.sqlExecute;

//需要说明网络服务器名称
//Account.jsp发送请求到名为Login的网络服务器
@WebServlet("/Login")
public class Login extends HttpServlet {

    public Login(){
        super();
    }
    @Override
    protected void doGet(HttpServletRequest request,HttpServletResponse response){
        try{
            response.getWriter().append("Served at: ").append(request.getContextPath());
            PrintWriter pw = response.getWriter();
            pw.append("sss");
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            System.out.println("账号是:" + username);
            System.out.println("密码是:" + password);
            sqlExecute se = new sqlExecute();
            if(password.equals(se.queryPassword(username))){
                System.out.println("登陆成功");
                //成功后跳转
                response.sendRedirect("index.jsp");
            }else{
                System.out.println("登陆失败");
                //失败后跳转
                response.sendRedirect("views/Account.jsp");
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

2.4 Register

Register.jsp中调用了Register方法,具体步骤基本和Login一致,但是执行的数据库操作不同

Login执行的是查询操作;Register执行的是插入操作

package com.servlet.register;


import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import com.mysql.sqlExecute;

//指定网络服务器名称
//Register.jsp中的请求发送到的是名为Register的服务器
@WebServlet("/Register")
public class Register extends HttpServlet {
    public Register(){
        super();
    }

    @Override
    public void doGet(HttpServletRequest request,HttpServletResponse response){
        try{
            response.getWriter().append("Served at: ").append(request.getContextPath());
            PrintWriter pw = response.getWriter();
            pw.append("sss");
            String nation = request.getParameter("region");
            String telephone = request.getParameter("phone");
            System.out.println("国家为:"+nation);
            System.out.println("电话为:"+telephone);
            sqlExecute se = new sqlExecute();
            se.insert(nation,telephone);
            response.sendRedirect("index.jsp");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

3 数据库方面

3.1 整体功能

在servlet配置完成后,前端就可以发送数据请求了,其后就是后端接受同时响应请求。在接受请求时,根据不同的操作对数据库进行不同的操作,例如登录就是查询数据库相关表单,注册就是在数据库相应表单中插入某些数据。在之后的代码优化中,用户修改个人信息即为数据库的update功能。

3.2 sqlDao

这一层是在数据库上的操作,通过sqlExecute类的获取的Connection对象conn连接数据库,并在数据库上进行一系列操作。在这一层,包括查询和更新两个主函数,另外就是查询列名辅助函数,辅助sqlExecute类中查询指定密码的方法实现。

package com.mysql;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import java.sql.ResultSetMetaData;

public class sqlDao {
    private Connection conn;
    /**
     * 构造函数
     * */
    public sqlDao(Connection n){
        this.conn = n;
    }
    /**
     * 更新操作
     * */
    public void update(String sql){
        System.out.println(sql+"已执行");
        try{
            Statement stmt = conn.createStatement();
            stmt.executeUpdate(sql);
            stmt.close();
        }catch(SQLException e){
            e.printStackTrace();
        }catch(NullPointerException e){
            System.out.println("请连接数据库");
        }
    }
    /**
     * 获取列名
     * */
    public Vector<String> selectTitle(String sql){
        Vector<String> temp = new Vector<>();
        try{
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            //获取列数
            ResultSetMetaData rsMd = rs.getMetaData();
            int columnCount = rsMd.getColumnCount();
            System.out.println(rs.next());
            //获取列名
            for(int i = 0; i < columnCount; i++){
                temp.add(rsMd.getColumnName(i+1));
            }
            rs.close();
            stmt.close();
        }catch(SQLException e){
            e.printStackTrace();
        }catch(NullPointerException e){
            System.out.println("请连接数据库");
        }
        return temp;
    }
    /**
     * 查询操作
     * */
    public Vector<Vector<String>> select(String sql){
        Vector<Vector<String>> r = new Vector<>();
        System.out.println(sql + "已执行");
        try{
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            int columnCount = rs.getMetaData().getColumnCount();
            while(rs.next()){
                Vector<String> temp = new Vector<>();
                r.add(selectTitle(sql));
                for(int i = 0; i < columnCount; i++){
                    temp.add(rs.getString(i+1));
                }
                r.add(temp);
            }
        }catch(SQLException e){
            e.printStackTrace();
        }catch(NullPointerException e){
            System.out.println("请连接数据库");
        }
        return r;
    }
}

3.3 sqlExecute

在这一层,根据名字也能判断出来这是一个与sql语句相关的类,此类用来执行不同的sql语句,不同的sql语句对应sqlDao里面的各种方法,sqlExecute类中将引用sqlDao的方法。另外就是,sqlExecute还控制数据库的连接。

package com.mysql;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.util.Vector;

public class sqlExecute {
    private static String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true";
    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String user;
    private static String password;
    private static Connection conn;
    private int max_id;

    //构造函数
    public sqlExecute(){
        this.user = "root";
        this.password = "159357";
        connListener cl = new connListener();
        //在构造sqlExecute对象时连接数据库
        cl.connect();
    }
    //连接监听
    private class connListener{
        public void connect(){
            try{
                Class.forName(driver);
                conn = DriverManager.getConnection(url,user,password);
                if(null!=conn){
                    System.out.println("成功连接数据库");
                }
            }catch(ClassNotFoundException | SQLException e){
                e.getStackTrace();
            }
        }
    }
    //查询指定用户的密码
    public String queryPassword(String username){
        String sql = "select * from users where username = '" + username +"';";
        sqlDao sd = new sqlDao(conn);
        Vector<Vector<String>> temp = sd.select(sql);
        int i,j,k;
        //暂时不考虑重名问题
        if(temp.get(1).contains(username)) {
            int cow = temp.size();
            int col = temp.get(0).size();
            //确定用户名所在列
            for(k = 0;k < col;k++){
                if(temp.get(0).get(k).equals("username")){
                    break;
                }
            }
            //确定密码所在列
            for(j = 0;j < col;j++){
                if(temp.get(0).get(j).equals("password")){
                    break;
                }
            }
            //确定用户名所在行
            for(i = 0;i<cow;i++){
                if(temp.get(i).get(k).equals(username)){
                    break;
                }
            }
            return temp.get(i).get(j);
        }else{
            System.out.println("此用户不存在");
            return null;
        }
    }
    //根据注册页面1进行数据库插入操作
    public void insert(String nation,String phone){
        max_id=findMax()+1;
        String sql = "insert into users values(" + max_id + ",'"+nation+"',null,null,'"+phone+"',null);";
        sqlDao sd = new sqlDao(conn);
        sd.update(sql);
    }
    //由于userid为主键不可为空,故而插入时需要指定最大id
    public int findMax(){
        String sql = "select max(userid) as max_id from users;";
        sqlDao sd = new sqlDao(conn);
        Vector<Vector<String>> r = sd.select(sql);
        int mid = Integer.parseInt(r.get(1).get(0));
        return mid;
    }
}

4 项目整体结构(树状图)

ps:由于图片比较多,目录会显得比较长,我把相关的图片目录都删除了,只要是

C:\LIXIANLEI\THEFOURTHWEEK\XIAOMI商城
│  Xiaomi商城.iml
│  
├─.idea
│  │  .gitignore
│  │  misc.xml
│  │  modules.xml
│  │  uiDesigner.xml
│  │  vcs.xml
│  │  workspace.xml
│  │  
│  ├─artifacts
│  │      Xiaomi_war_exploded.xml
│  │      
│  └─libraries
│          mysql_connector_java_8_0_21.xml
│          
├─doc
│  │  tree.txt
│  │  tree1.txt
│  │  前后端交互.md
│  │  
│  └─img
│          Debug配置-1.png
│          Debug配置-2.png
│          Debug配置-3.png
│          项目配置-1.png
│          项目配置-2.png
│          项目配置-3.png
│          
├─lib
│      mysql-connector-java-8.0.21.jar
│      
├─out
│  ├─artifacts
│  │  └─Xiaomi_war_exploded
│  │      │  index.jsp
│  │      │  
│  │      ├─.idea
│  │      │  ├─artifacts
│  │      │  └─libraries
│  │      ├─css
│  │      │      Account.css
│  │      │      base.css
│  │      │      index.css
│  │      │      load.css
│  │      │      register.css
│  │      │      reset.css
│  │      │      style.css
│  │      │      
│  │      ├─img
│  │      │          
│  │      ├─js
│  │      ├─lib
│  │      ├─META-INF
│  │      │      context.xml
│  │      │      
│  │      ├─src
│  │      │  └─com
│  │      │      └─servlet
│  │      │          └─login
│  │      ├─views
│  │      │      Account.jsp
│  │      │      Register.jsp
│  │      │      
│  │      ├─web
│  │      │  ├─css
│  │      │  ├─img
│  │      │  │  └─Router
│  │      │  ├─js
│  │      │  ├─META-INF
│  │      │  ├─views
│  │      │  └─WEB-INF
│  │      └─WEB-INF
│  │          │  web.xml
│  │          │  
│  │          ├─classes
│  │          │  │  Account.jsp
│  │          │  │  Register.jsp
│  │          │  │  
│  │          │  └─com
│  │          │      ├─mysql
│  │          │      │      sqlDao.class
│  │          │      │      sqlExecute$1.class
│  │          │      │      sqlExecute$connListener.class
│  │          │      │      sqlExecute.class
│  │          │      │      
│  │          │      └─servlet
│  │          │          ├─login
│  │          │          │      Login.class
│  │          │          │      
│  │          │          └─register
│  │          │                  Register.class
│  │          │                  
│  │          └─lib
│  │                  mysql-connector-java-8.0.21.jar
│  │                  
│  └─production
│      └─Xiaomi商城
│          │  Account.jsp
│          │  Register.jsp
│          │  
│          └─com
│              ├─mysql
│              │      sqlDao.class
│              │      sqlExecute$1.class
│              │      sqlExecute$connListener.class
│              │      sqlExecute.class
│              │      
│              └─servlet
│                  ├─login
│                  │      Login.class
│                  │      
│                  └─register
│                          Register.class
│                          
├─src
│  └─com
│      ├─mysql
│      │      sqlDao.java
│      │      sqlExecute.java
│      │      
│      └─servlet
│          ├─login
│          │      Login.java
│          │      
│          └─register
│                  Register.java
│                  
└─web
    │  index.jsp
    │  
    ├─css
    │      Account.css
    │      base.css
    │      index.css
    │      load.css
    │      register.css
    │      reset.css
    │      style.css
    │      
    ├─img
    │          
    ├─js
    ├─META-INF
    │      context.xml
    │      
    ├─views
    │      Account.jsp
    │      Register.jsp
    │      
    └─WEB-INF
            web.xml
            

5 常见问题汇总

下面的问题会出现是笔者一点点磨出来的,正所谓“久病成医”,但是我也没有生过全部的病,如果下面没有你想要的答案,别怪我哟,可以私信我咱们慢慢讨论(好吧,王婆卖瓜了一次)

5.1 404问题

5.1.1 jsp文件存放位置错误

我也是刚接触前后端交互方面编程,但是404和405我已经遇见无数次了。一般有很多种情况,例如找不到相关的资源。首先就是你要确定你新建的jsp文件不能存放在WEB-INF文件夹下,就是不能和web.xml文件放在同一个文件夹。放在web根目录下或者新建一个目录都可以。网上有相应的博客,这里就不贴链接了。

5.1.2 修改jsp文件后没有修改路径

另外就是在修改过jsp文件位置后,并没有在其余与此jap文件相关或者存在跳转的文件中的地址,例如,我的Account.jsp文件中有两个跳转,但这时我将index.jsp文件移动到了views文件夹中,但是没有修改相应的路径,例如我的web.xml文件中欢迎界面就是index.jsp,但是根目录下的index.jsp已经被我移走了,这样再就运行就会提示404错误,找不到index.jsp资源

5.1.3 相对路径问题

如果这两个地方都没有问题,那就是有一个小细节没有注意到。因为对于我们的项目而言。在运行时,前端的根目录就是web文件夹,故而在书写相对路径的时候需要多留几个心眼。

5.2 点击登录无反应

5.2.1 jsp文件中问题

首先咱们先理清一下思路,首先我们需要在jsp文件中创建表单,将此表单通过一定的方法发送到指定的网络服务器上,等待相关的网络服务器响应请求。既然是这样,这里面就有几个容易犯错的点。

  • 单词拼写错误(不要笑,不要把form拼写成from,这两个词很像的,我有次因为这个调试了一下午,哭死在学习英语和实现前后端交互的路上)
  • 登录按钮那一块类型一定不要写成"button",一定要写成"submit",即type="submit"
  • 然后就是看有没有对应的规则限制你的输入,如果有的话,查看你的输入是否符合规则,不符合规则并且没有任何错误提示在代码中说明的话,点击登录也是没有反应的
  • 再一个就是检查from表单对应的服务器是否正确,是action属性,例如实现登录功能时,action="Login"(按照我的代码哈)
  • 最后一个就是选择的方法,如果在你的后端代码改写的是doPost方法,那么method="post";如果改写的是doGet方法,那么method="get",这也是form表单的属性之一
5.2.2 后端代码问题

。因为对于我们的项目而言。在运行时,前端的根目录就是web文件夹,故而在书写相对路径的时候需要多留几个心眼。

  • 8
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值