>  기사  >  Java  >  Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

巴扎黑
巴扎黑원래의
2017-08-10 15:37:212441검색


예전에는 사용자 정보를 저장하기 위해 데이터베이스를 나타내는 xml 파일을 만들었습니다. 이제 데이터베이스 관련 지식을 배웠으므로 xml을 데이터베이스로 바꾸고 데이터베이스 응용 프로그램으로 업그레이드해야 합니다.
이전 프로젝트를 복사해서 복사할 때 이전 프로젝트 이름이 day09_user라고 가정하고 이제 복사해서 복사해서 프로젝트 이름을 day14_user로 바꾸고 이제 tomcat 서버에 직접 배포하면 day14_user JavaWeb 애플리케이션 매핑이 됩니다. 가상 디렉터리는 여전히 "/day09_user"이며 동일한 이름 "/day14_user"를 가진 가상 디렉터리에 매핑되지 않습니다. 이는 종종 간과되는 문제입니다.
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

데이터베이스 애플리케이션으로 업그레이드

  • 데이터베이스 드라이버 가져오기
    Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

  • 애플리케이션에 해당하는 라이브러리 및 테이블 생성

    create database day14_user;use day14_user;create table users
    (
        id varchar(40) primary key,
        username varchar(40) not null unique,
        password varchar(40) not null,
        email varchar(100) not null unique,
        birthday date,
        nickname varchar(40) not null);
    • 1

    • 2

    • 3

    • 4 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

    • src 디렉터리에 db.properties 파일을 생성합니다. , 다음과 같이 그림과 같습니다:
    • db.properties에 MySQL 데이터베이스의 연결 정보를 작성합니다. 코드는 다음과 같습니다.

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/day14_userusername=root
      password=yezi#driver=oracle.jdbc.driver.OracleDriver#url=jdbc:oracle:thin:@localhost:1521:orcl#username=system#password=111
    • 1
    • 2
    • 3
    • 4
    • 5
  • 6
    Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

    7
    • 8

    • 9

    • 10

    • 11

    • 12

    • 13

    • 14

    • 15

    • 16

    • 17

    • Rewriting UserDao
    • 이제 UserDao 인터페이스의 모든 메소드를 다시 작성하고 UserD의 구현 클래스를 생성해야 합니다. ao 인터페이스 cn.itcast.dao.impl 패키지 ——UserDaoJdbcImpl, 아래와 같습니다.

    • 처음에 작성한 내용이 최종 코드가 아니므로 공개 사용자 찾기(문자열 사용자 이름, 문자열 비밀번호)에 중점을 둘 것입니다. 로그인 방법.
    • 먼저 명령문 개체를 사용하여 public User find(String username, String Password) 메서드를 다시 작성합니다. 코드는 다음과 같습니다.

      @Override
      public User find(String username, String password) {
          Connection conn = null;
          Statement st = null; // PreparedStatement预防SQL注入
          ResultSet rs = null;
          try {
              conn = JdbcUtils.getConnection();        st = conn.createStatement();
      
              String sql = "select * from users where username='"+username+"' and password='"+password+"'";
              rs = st.executeQuery(sql);
              if (rs.next()) {
                  User user = new User();
                  user.setBirthday(rs.getDate("birthday"));
                  user.setEmail(rs.getString("email"));
                  user.setId(rs.getString("id"));
                  user.setNickname(rs.getString("nickname"));
                  user.setPassword(rs.getString("password"));
                  user.setUsername(rs.getString("username"));
                  return user;
              }
              return null;
          } catch (Exception e) {
              // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛
              throw new RuntimeException(e);
          } finally {
              JdbcUtils.release(conn, st, rs);
          }
      }1234567891011121314151617181920212223242526272829

      Java에서 예외 처리가 정말 귀찮습니다. 예외 처리 원칙에 대해 이야기해 보겠습니다.
    • 학계에서는 Java 예외 처리에 대해 많은 논란이 있습니다. 크게 세 가지 학파로 나뉩니다.
    • Java 언어 디자이너 - Gao 사령관 그가 디자인한 Java 언어에는 컴파일 타임 예외와 런타임 예외. Java 이후 언어는 그가 설계했기 때문에 컴파일 타임 예외도 합리적으로 존재해야 한다고 믿습니다.
    • "Thinking In Java"의 저자는 Java 언어의 컴파일 타임 예외는 쓰레기이며 예외는 런타임 예외로 변환되어 버려야 한다고 믿습니다.
    • Spring 작성자는 위 두 사람의 의견을 완화했습니다. 예외가 있는 프로그램이 있으면 어떻게 해야 할까요? 단지 상위 프로그램이 처리할 수 있는지 여부에 따라 달라지나요? 처리할 수 없는 경우 런타임 예외로 변환되어 발생합니다. 처리할 수 있는 경우 컴파일 타임 예외로 변환되어 직접 발생합니다.
    • 그래서 Spring 작성자의 관점을 채택하는 것이 가장 좋습니다. 그러면 우리의 접근 방식은 다음과 같습니다. 예외가 있는 프로그램이 있는 경우 어떻게 해야 합니까? 이는 프로그램의 상위 계층에서 예외를 처리하도록 할지 여부에 따라 달라집니다. 상위 프로그램에서 처리하기를 원하지 않으면 상위 프로그램에 문제가 발생하지 않도록 런타임 예외로 전환하여 상위 프로그램에서 처리하도록 하세요. 이를 컴파일 타임 예외로 바꾸고 직접 발생시킵니다.
    실제 개발에서는 Dao 레이어(데이터 접근 레이어)에 커스텀 예외 클래스 - DaoException 등 레이어별로 커스텀 예외를 작성하는 것이 가장 좋습니다.
다음과 같이 cn.itcast.Exception 패키지에 예외 클래스 DaoException을 생성합니다.

여기에 그림 설명 쓰기

DaoException 클래스 코드는 다음과 같습니다.

public class DaoException extends RuntimeException {    public DaoException() {        // TODO Auto-generated constructor stub
    }    public DaoException(String message) {        super(message);        // TODO Auto-generated constructor stub
    }    public DaoException(Throwable cause) {        super(cause);        // TODO Auto-generated constructor stub
    }    public DaoException(String message, Throwable cause) {        super(message, cause);        // TODO Auto-generated constructor stub
    }    public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {        super(message, cause, enableSuppression, writableStackTrace);        // TODO Auto-generated constructor stub
    }

}123456789101112131415161718192021222324252627

Dao 예외를 던지도록 맞춤화하고 싶은데, 왜 그럴까요? Dao 예외를 던지도록 사용자 정의하는 것의 가장 큰 장점은 이 예외를 발생시키는 것입니다. 누군가 이 예외를 수신하면 예외의 클래스 이름을 보는 즉시 어떤 레이어가 문제인지 알 수 있고 이를 빠르게 찾을 수 있습니다. 문제를 찾기 위한 레이어입니다. 각 레이어마다 맞춤 예외를 두는 것이 가장 좋습니다. Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명그런 다음 UserDaoJdbcImpl 클래스의 public User find(String 사용자 이름, 문자열 비밀번호) 메소드를 다음과 같이 수정하세요.
@Override
public User find(String username, String password) {
    Connection conn = null;
    Statement st = null; // PreparedStatement预防SQL注入
    ResultSet rs = null;
    try {
        conn = JdbcUtils.getConnection();        st = conn.createStatement();

        String sql = "select * from users where username='"+username+"' and password='"+password+"'";
        rs = st.executeQuery(sql);
        if (rs.next()) {
            User user = new User();
            user.setBirthday(rs.getDate("birthday"));
            user.setEmail(rs.getString("email"));
            user.setId(rs.getString("id"));
            user.setNickname(rs.getString("nickname"));
            user.setPassword(rs.getString("password"));
            user.setUsername(rs.getString("username"));
            return user;
        }
        return null;
    } catch (Exception e) {
        // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛        /*
         * 自定义一个Dao异常抛出去,为什么呢?
         * 自定义一个Dao异常抛出去最大的好处就是我把这个异常抛出去,人家收到这个异常,一看到这个异常的类名,
         * 就能知道到底是哪一层出问题了,他就可以快速定位到这一层来找问题。最好每一层都要有一个自定义异常。
         */
        throw new DaoException(e);
    } finally {
        JdbcUtils.release(conn, st, rs);
    }
}1234567891011121314151617181920212223242526272829303132333435

实现service层和dao层的解耦

我们以前在开发service层(service层对web层提供所有的业务服务)时,编写UserService接口的具体实现类——UserServiceImpl时,业务逻辑层和数据访问层是紧密联系在一起的,所以业务逻辑层和数据访问层要解耦(希望底层Dao层代码换了,业务逻辑层的代码一行都不改,这时要用到工厂设计模式),要解耦,有两种方法:

  • 工厂模式

  • Spring

现在我们重点关注工厂模式。这时我们要定义一个Dao工厂,新建一个cn.itcast.factory包,在包中创建一个Dao工厂——DaoFactory,如下所示:
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명
工厂一般要设计成单例的,为什么呢?
答:工厂设计成单例的,工厂的对象在内存中只有一个,目的是希望所有的Dao都由一个工厂来生产。假设不把工厂设计成单例的,将来Dao由不同的工厂来生产,你觉得所有的Dao由一个工厂来生产好,还是由不同的工厂来生产好?答案显然是由一个工厂来生产好,将来维护起来好维护。
我们先编写DaoFactory类的代码为:

public class DaoFactory {    private Properties daoConfig = new Properties();    private DaoFactory() {}    private static DaoFactory instance = new DaoFactory();    public static DaoFactory getInstance() {        return instance;
    }    //                      UserDao.class(接口类型)    //                      DepartmentDao.class(接口类型)       public <T> T createDao(Class<T> clazz) {        // clazz.getName(); // 返回UserDao接口的完整名称:cn.itcast.dao.UserDao
        String name = clazz.getSimpleName(); // 返回UserDao接口的简单名称:UserDao

        DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
        ......
    }
}123456789101112131415161718192021

以上的代码好吗?显然这样做并不好,每次别人调用createDao方法,都会去读一下配置文件dao.properties,但此配置文件在整个系统里面只要读取一次就好,没必要老去读,即以下这行代码只需运行一次。

DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");1

那么这行代码可以放到静态代码块里。
现在将以上代码修改为:

public class DaoFactory {    static {
        DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
    }    private Properties daoConfig = new Properties();    private DaoFactory() {}    private static DaoFactory instance = new DaoFactory();    public static DaoFactory getInstance() {        return instance;
    }    //                      UserDao.class(接口类型)    //                      DepartmentDao.class(接口类型)       public <T> T createDao(Class<T> clazz) {        // clazz.getName(); // 返回UserDao接口的完整名称:cn.itcast.dao.UserDao
        String name = clazz.getSimpleName(); // 返回UserDao接口的简单名称:UserDao        // DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
        ......
    }
}12345678910111213141516171819202122232425

以上这样做并没有不好,但是对于现在而言还有一种做法,DaoFactory这个类被设计成单例的,所以其构造函数仅执行一次,所以可放到DaoFactory这个类的构造函数里面。所以最后完整的代码如下:

public class DaoFactory {    /*
    static {
        DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
    }
    */    private Properties daoConfig = new Properties();    private DaoFactory() {
        InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");        try {
            daoConfig.load(in);
        } catch (IOException e) {            throw new RuntimeException(e);
        }
    }    private static DaoFactory instance = new DaoFactory();    public static DaoFactory getInstance() {        return instance;
    }    //                      UserDao.class(接口类型)    //                      DepartmentDao.class(接口类型)       public <T> T createDao(Class<T> clazz) {        // clazz.getName(); // 返回UserDao接口的完整名称:cn.itcast.dao.UserDao
        String name = clazz.getSimpleName(); // 返回UserDao接口的简单名称:UserDao        // DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");

        String className = daoConfig.getProperty(name);        try {
            T dao = (T) Class.forName(className).newInstance(); // 创建实例对象            return dao;
        } catch (Exception e) {            throw new RuntimeException(e);
        }
    }
}123456789101112131415161718192021222324252627282930313233343536373839

然后在src目录下创建一个dao.properties文件,如下图所示:
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명  
在db.properties中内容如下所示:

UserDao=cn.itcast.dao.impl.UserDaoJdbcImpl1

实现service层和dao层的解耦,UserService接口的具体实现类——UserServiceImpl只须修改为:

// 对web层提供所有的业务服务public class BusinessServiceImpl {    /*
     * 业务逻辑层和数据访问层要解耦——希望底层Dao层代码换了,业务逻辑层的代码一行都不改,这时要用到工厂设计模式
     * 要解耦,有两张方法:
     * 1. 工厂模式
     * 2. spring
     */    // private UserDao dao = new UserDaoJdbcImpl();    private UserDao dao = DaoFactory.getInstance().createDao(UserDao.class);    // 对web层提供注册服务    public void register(User user) throws UserExistException {        // 先判断当前要注册的用户是否存在        boolean b = dao.find(user.getUsername());        if(b) {            /*
             * service层是由web层来调用的,
             * 发现当前要注册的用户已存在,要提醒给web层,web层给用户一个友好提示
             * 希望web层一定要处理,处理之后给用户一个友好提示,所以抛一个编译时异常,
             * 抛运行时异常是不行的,因为web层可处理可不处理
             */            throw new UserExistException(); // 发现要注册的用户已存在,则给web层抛一个编译时异常,提醒web层处理这个异常,给用户一个友好提示。
        } else {
            user.setPassword(ServiceUtils.md5(user.getPassword()));
            dao.add(user);
        }
    }    // 对web层提供登录服务    public User login(String username, String password) { // aaa 123
        password = ServiceUtils.md5(password); // 要把密码md5一把再找        return dao.find(username, password);
    }
}123456789101112131415161718192021222324252627282930313233343536

防范sql注入攻击

SQL注入是用户利用某些系统没有对输入数据进行充分的检查,从而进行恶意破坏的行为。
例如,statement存在sql注入攻击问题,假如登录用户名采用' or 1=1 or name='
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명

对于防范SQL注入,可以采用PreparedStatement取代Statement。

PreparedStatement对象介绍

PreperedStatement是Statement的孩子,它的实例对象可以通过调用Connection.preparedStatement()方法获得,相对于Statement对象而言:

  • PreperedStatement可以避免SQL注入的问题。

  • Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。

  • 并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。

使用PreparedStatement改写UserDaoJdbcImpl类的public User find(String username, String password)方法。

@Override
public User find(String username, String password) {
    Connection conn = null;
    PreparedStatement st = null; // PreparedStatement预防SQL注入
    ResultSet rs = null;
    try {
        conn = JdbcUtils.getConnection();
        String sql = "select * from users where username=? and password=?";        st = conn.prepareStatement(sql); // 预编译这条sql语句        st.setString(1, username);        st.setString(2, password);

        rs = st.executeQuery();
        if (rs.next()) {
            User user = new User();
            user.setBirthday(rs.getDate("birthday"));
            user.setEmail(rs.getString("email"));
            user.setId(rs.getString("id"));
            user.setNickname(rs.getString("nickname"));
            user.setPassword(rs.getString("password"));
            user.setUsername(rs.getString("username"));
            return user;
        }
        return null;
    } catch (Exception e) {
        // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛
        throw new DaoException(e);
    } finally {
        JdbcUtils.release(conn, st, rs);
    }
}12345678910111213141516171819202122232425262728293031

到此为止,我们就可以完整地写出UserDaoJdbcImpl类了,其完整代码如下:

public class UserDaoJdbcImpl implements UserDao {    @Override    public void add(User user) {
        Connection conn = null;        // Statement st = null;
        PreparedStatement st = null;
        ResultSet rs = null;        try {
            conn = JdbcUtils.getConnection();
            String sql = "insert into users(id,username,password,email,birthday,nickname) values(?,?,?,?,?,?)";
            st = conn.prepareStatement(sql);
            st.setString(1, user.getId());
            st.setString(2, user.getUsername());
            st.setString(3, user.getPassword());
            st.setString(4, user.getEmail());
            st.setDate(5, new java.sql.Date(user.getBirthday().getTime()));
            st.setString(6, user.getNickname());            // st = conn.createStatement();            // String sql = "insert into users(id,username,password,email,birthday,nickname) values(&#39;"+user.getId()+"&#39;,&#39;"+user.getUsername()+"&#39;,&#39;"+user.getPassword()+"&#39;,&#39;"+user.getEmail()+"&#39;,&#39;"+user.getBirthday().toLocaleString()+"&#39;,&#39;"+user.getNickname()+"&#39;)";            // int num = st.executeUpdate(sql);            int num = st.executeUpdate();            if(num < 1) {                throw new RuntimeException("注册用户失败!!!");
            }
        } catch (Exception e) {            // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛            /*
             * 自定义一个Dao异常抛出去,为什么呢?
             * 自定义一个Dao异常抛出去最大的好处就是我把这个异常抛出去,人家收到这个异常,一看到这个异常的类名,
             * 就能知道到底是哪一层出问题了,他就可以快速定位到这一层来找问题。最好每一层都要有一个自定义异常。
             */            /*
             * gosling    Thinking In Java   Spring
             * Spring作者——你这个有程序有异常,你拿到这个异常,怎么做呢?就看上一层程序能不能处理?
             *            如果不能处理,就转为运行时异常抛出去,如果能处理,就转为编译时异常直接往上抛出去。
             *            
             * 我们的处理方法——你这个有程序有异常,你拿到这个异常,怎么做呢?就看异常你希不希望上一层程序处理?
             *            如果你不希望上一层程序处理,免得给上一层程序带来麻烦,就转为运行时异常抛出去,如果你希望上一层程序处理,就转为编译时异常直接往上抛出去。
             */            // throw new RuntimeException(e);            throw new DaoException(e);
        } finally {
            JdbcUtils.release(conn, st, rs);
        }
    }    // username=&#39;or 1=1 or username=&#39;   password=""    @Override    public User find(String username, String password) {
        Connection conn = null;
        PreparedStatement st = null; // PreparedStatement预防SQL注入
        ResultSet rs = null;        try {
            conn = JdbcUtils.getConnection();
            String sql = "select * from users where username=? and password=?";
            st = conn.prepareStatement(sql); // 预编译这条sql语句
            st.setString(1, username);
            st.setString(2, password);

            rs = st.executeQuery();            if (rs.next()) {
                User user = new User();
                user.setBirthday(rs.getDate("birthday"));
                user.setEmail(rs.getString("email"));
                user.setId(rs.getString("id"));
                user.setNickname(rs.getString("nickname"));
                user.setPassword(rs.getString("password"));
                user.setUsername(rs.getString("username"));                return user;
            }            return null;
        } catch (Exception e) {            // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛            throw new DaoException(e);
        } finally {
            JdbcUtils.release(conn, st, rs);
        }
    }    @Override    public boolean find(String username) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;        try {
            conn = JdbcUtils.getConnection();
            String sql = "select * from users where username=?";
            st = conn.prepareStatement(sql);
            st.setString(1, username);

            rs = st.executeQuery();            if (rs.next()) {                return true;
            }            return false;
        } catch (Exception e) {            // 异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛            throw new DaoException(e);
        } finally {
            JdbcUtils.release(conn, st, rs);
        }
    }

}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108

面试题:Statement和PreparedStatement的区别。
答:

  1. PreparedStatement是Statement的孩子。

  2. PreparedStatement可以防止sql注入的问题。

  3. PreparedStatement会对sql语句进行预编译,以减轻数据库服务器的压力。

就像xxx.javaxxx.classJVM执行一样,sql语句编译数据库执行
开发完数据访问层,一定要对程序已编写好的部分代码进行测试,做一步,测试一步,以免整个程序完成后由于页面太多或者是代码量太大给查找错误造成更大的负担!所以,在juint.test包下创建了一个UserDaoJdbcTest类。  
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명
UserDaoJdbcTest类的具体代码如下:

public class UserDaoJdbcTest {
    @Test    public void testAdd() {
        User user = new User();
        user.setBirthday(new Date());
        user.setEmail("bb@sina.com");
        user.setId("2142354354");
        user.setNickname("李子");
        user.setUsername("bbbb");
        user.setPassword("123");

        UserDao dao = new UserDaoJdbcImpl();
        dao.add(user);
    }

    @Test    public void testFind() {
        UserDao dao = new UserDaoJdbcImpl();
        User user = dao.find("bbbb", "123"); // 在断点模式Watch
        System.out.println(user);
    }

    @Test    public void testFindByUsername() {
        UserDao dao = new UserDaoJdbcImpl();
        System.out.println(dao.find("bbbb"));
    }
}12345678910111213141516171819202122232425262728

经测试,没发现任何错误。同样也要对业务逻辑层已编写好的部分代码进行测试,在juint.test包下创建了一个ServiceTest类。
Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명
ServiceTest类的具体代码如下:

public class ServiceTest {

    @Test    public void testRegister() {
        User user = new User();
        user.setBirthday(new Date());
        user.setEmail("bb@sina.com");
        user.setId("2142354354");
        user.setNickname("李子");
        user.setUsername("lizi");
        user.setPassword("123");

        BusinessServiceImpl service = new BusinessServiceImpl();        try {
            service.register(user);
            System.out.println("注册成功!!!");
        } catch (UserExistException e) {
            System.out.println("用户已存在");
        }
    }

    @Test    public void testLogin() {
        BusinessServiceImpl service = new BusinessServiceImpl();
        User user = service.login("lizi", "123");
        System.out.println(user);
    }
}12345678910111213141516171819202122232425262728

经测试,没发现任何错误。
到此,对基于Servlet+JSP+JavaBean开发模式的用户登录注册的升级改造圆满完成。


위 내용은 Servlet+JSP+JavaBean 개발 모델 기반 사용자 로그인 등록을 위한 업그레이드 튜토리얼에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.