Java_web入门
Java_web概述
Java_web应用由一组Servlet、Html页、类以及其它可绑定的资源构成。它可以在各种供应商提供的Servlet规范的Servlet容器中运行。
Java_web包含以下内容:
-
Servlet
-
JSP
-
实体类
-
静态文档如HTML,图片等
-
描述web应用的信息web.xml
Servlet与Servlet容器
Java_web目录结构
Servlet
Servlet功能
-
创建并返回基于客户请求的动态HTML页面
-
创建可嵌入到现有HTML页面中的部分HTML页面
-
与其他服务器资源(如数据库或基于Java的应用程序)进行通信
Servlet容器响应客户请求
第一个servlet及其在web.xml中的配置
package com.why.study2.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
<!-- 配置和映射Servlet-->
<servlet>
<!-- Servlet注册名-->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet全类名-->
<servlet-class>com.why.study2.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 需要和某一节点的servlet-name保持一致-->
<servlet-name>helloServlet</servlet-name>
<!-- 映射具体的访问路径-->
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
同意Servlet可映射多个servletmapping,即多个servletmapping的<servlet-name>可相同
带扩展名/不能加*,带 *不能加扩展名,即/ *.html不合法
Servlet容器
-
创建Servlet,并调用Servlet的相关生命周期方法
-
运行Servlet,JSP,Filter,Listener,Tag等的软件环境
Servlet 生命周期的方法
以下方法都是由Servlet容器负责调用:
-
构造器:只有第一次请求Servlet时创建Servlet的实例,调用构造 器,Servlet是单实例的,非线程安全
-
init方法:对象只被调用一次,创建好实例后立即被调用,用于初 始化Servlet
-
service方法:每次请求都会调用service方法,实际用于响应请求
-
destroy方法:只被调用一次,web应用被卸载前调用,释放Servlet占用的资源
load-on-startup,指定Servlet被创建的时机
<!-- 配置和映射Servlet-->
<servlet>
<!-- Servlet注册名-->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet全类名-->
<servlet-class>com.why.study2.servlet.HelloServlet</servlet-class>
<!-- 可以指定Servlet被创建的时机,数字越小越早该Servlet先被创建-->
<load-on-startup>1</load-on-startup>
</servlet>
ServletConfig对象
封装Servlet的配置信息,并且可以获取ServletContext对象
-
配置Servlet的初始化参数
<!-- 配置Servlet初始化参数,要放在<load-on-startup>之前-->
<init-param>
<!-- 初始化参数名-->
<param-name>password</param-name>
<!-- 初始化参数值-->
<param-value>1230</param-value>
</init-param>
<init-param>
<!-- 初始化参数名-->
<param-name>user</param-name>
<!-- 初始化参数值-->
<param-value>why</param-value>
</init-param> -
获取初始化参数
-
getInitParameter(String name):获取指定参数名的初始化参数
-
getInitParameterNames():获取参数名组成的Enumeration对象
String user = servletConfig.getInitParameter("user"); System.out.println("名字"+user); String password = servletConfig.getInitParameter("password"); System.out.println("密码"+password); Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()){ String s = initParameterNames.nextElement(); System.out.println(s); } -
-
获取Servlet配置名称
1. String servletName = servletConfig.getServletName(); System.out.println(servletName);
ServletContext接口
-
可由ServletConfig获取
-
该对象代表当前web应用,获取当前web应用的各种信息
-
获取当前web应用的初始化参数
配置当前web应用的初始化参数
<!-- 配置当前web应用的初始化参数--> <context-param> <param-name>driver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param> <context-param> <param-name>jdbcUrl</param-name> <param-value>jdbc:mysql:///atguigu</param-value> </context-param>获取参数
//获取ServletContext对象 ServletContext servletContext = servletConfig.getServletContext(); String driver = servletContext.getInitParameter("driver"); System.out.println(driver); Enumeration<String> initParameterNames1 = servletContext.getInitParameterNames(); while (initParameterNames1.hasMoreElements()){ String s = initParameterNames1.nextElement(); System.out.println(s); -
获取当前某一web应用的服务器的绝对路径
//获取当前web应用服务器上发布的的绝对路径 String realPath = servletContext.getRealPath("HelloServlet.java"); System.out.println(realPath); -
获取当前web应用的名称
//获取当前web应用服务器上发布的的绝对路径 String realPath = servletContext.getRealPath("HelloServlet.java"); System.out.println(realPath); -
获取当前web应用对应的某一个文件的输入流
//获取文件输入流 InputStream resourceAsStream = servletContext.getResourceAsStream("WEB-INF/classes/a.properties"); System.out.println(resourceAsStream); -
attribute相关的方法
HTTP协议 GET & POST 请求
-
GET请求
在浏览器输入某个url地址或点击一个超链接时,浏览器一定是get请求
“<form>”表单可设置get请求
使用get请求有限制,一般为1kb以下
-
POST请求
form表单指定为post请求时才可为post请求
文件上传必须使用post请求
ServletRequest,封装请求信息
其中主要代码写于service中,它用于应答每次的请求
-
根据提交参数返回提交的内容
String user = servletRequest.getParameter("user"); String password = servletRequest.getParameter("password"); System.out.println("user "+user+" password "+password); -
根据请求参数名,返回请求参数返回对应的字符串
String[] interestings = servletRequest.getParameterValues("interesting"); System.out.println(Arrays.toString(interestings));用于返回提交的多选框的内容
-
返回参数名对应的Enumeration对象,类似于ServletConfig(或ServletContext)
Enumeration<String> parameterNames = servletRequest.getParameterNames(); System.out.println(parameterNames);
-
返回请求参数的键值对,key——参数名,value——参数值,string数组类型
Map<String, String[]> parameterMap = servletRequest.getParameterMap(); System.out.println(parameterMap);
ServletResponse,封装响应信息
-
打印字符串到浏览器页面
PrintWriter writer = servletResponse.getWriter(); writer.println("hello java_web..."); -
设置响应类型
返回word类型,需要返回的类型可取tomcat的config目录下的web.xml文件中查找
servletResponse.setContentType("application/msword");
GenericServlet,定义一个普遍的Servlet,其余Servlet继承此类
由于Servlet接口中的方法很多都不需要,所有我们写一个新的GnericServlet类继承Servlet创建Servlet时只需继承GnericServlet即可
-
GenericServlet.java
package com.why.servlet; import javax.servlet.*; import java.io.IOException; public abstract class GenericServlet implements Servlet { //定义私有属性 private ServletConfig servletConfig; public GenericServlet() { } @Override public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig; } @Override public ServletConfig getServletConfig() { //得到servletConfig return this.servletConfig; } @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException ; @Override public String getServletInfo() { return null; } @Override public void destroy() { } } -
自定义的Servlet
package com.why.servlet; import javax.servlet.*; import java.io.IOException; public class LoginServlet extends GenericServlet{ public LoginServlet() { } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { String username = servletRequest.getParameter("username"); String password = servletRequest.getParameter("password"); String username1 = getServletConfig().getServletContext().getInitParameter("username"); String password1 = getServletConfig().getServletContext().getInitParameter("password"); if (username!=null&&username.equals(username1)&&password!=null&&password.equals(password1)){ servletResponse.getWriter().println(username); servletResponse.getWriter().println(password); servletResponse.getWriter().println("欢迎回来"+username+"!"); }else { servletResponse.getWriter().println("用户名或密码有误,请重新登录!"); } } }HttpServlet
传统servlet不能很好区别post和get方法
package com.why.study2.servlet;
import javax.servlet.ServletException;
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 java.util.Arrays;
JSP
JSP概述
-
动态网页,希望在浏览器页面中编写Java代码,简化Servlet
-
举例:
<% -
JSP可放置在web应用除了WEB-INF中的任何目录下
-
JSP本质上是一个Servlet
JSP页面的9个隐含对象
-
PageContext pageContext = null; 配置页面上下文,可从该对象获取到其他八个隐含对象,也可获取到其他信息(自定义标签时使用);
-
HttpSession session = null;
-
ServletConfig config = null; 使用时需要映射jsp,同servlet
-
ServletContext application = null;
-
JspWriter out = null; 调用out.println(),可把字符串打印在浏览器页面上;
-
Object page = this; 指向当前JSP对应的Servlet对象的引用,几乎不使用;
-
request;
-
response,几乎不会使用。
使用<% %>编写代码在此位置,可用到这八个隐含对象(实际上还有exception隐含对象)
exception使用需要一定的条件,要有声明<%@ page isErrorPage="true" %>
隐含对象不需要声明即可使用
jsp换行可通过<% %>换行,可嵌套至html中
JSP指令
-
<%@page ... %> 定于一网页依赖属性,比如脚本语言、error页面、缓存需求等
一个JSP页面可包含多个page指令
语法格式:
<%相关属性:
-
<%@ include ... %> 包含其他文件被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。
指令格式:
<% -
<%@taglib ... %> 引入标签库定义。JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。
Taglib指令引入一个自定义标签集合的定义,包括库路径、自定义标签。
指令格式:
<%
JSP页面的请求的转发和重定向
本质区别:请求的撞飞只发出一次请求,重定向多次请求
-
转发
request.getRequestDispatcher("other.jsp").forward(request, response); -
重定向
response.sendRedirect("other.jsp");
JSP域对象及其属性有关的方法
解决中文乱码问题
-
page指令字符编码集要支持中文
-
post请求request之前设置页面编码格式
request.setCharacterEncoding("UTF-8"); -
GET请求tomcat有问题
重新配置tomcat
MVC开发模式
MVC概述
Model-View-Controller,即为MVC。
-
Model层:包括业务处理层Service和数据访问层Dao。
Dao数据访问层主要是对数据库中一些操作地封装。
Service业务处理层主要是用作将从Controller层获取地数据和数据库的数据进行桥接,对复杂的业务逻辑进行处理,比如事务处理
-
Controller层:指控制部分,是对View层提交的请求为其设置对应的Servlet进行特定功能的处理,充当中介的作用
-
View层:视图部分,如jsp或html页面
不推荐跨层操作,各层之间耦合度要低,即独立性高
MVC模式开发web应用示例
创建工程,工程目录
创建数据库mvcproject
设计user表
entity包中创建User实体类
package com.why.study2.entity;
import java.util.Date;
import java.util.Objects;
/**
* 用户类
* @author why
*/
public class User {
/**
* 用户编号
*/
private Integer id;
/**
* 用户名
*/
private String username;
/**
* 用户密码
*/
private String password;
/**
* 用户电话
*/
private String phoneNo;
/**
* 用户地址
*/
private String address;
/**
* 用户注册日期
*/
private Date regDate;
public User(Integer id, String username, String password, String phoneNo, String address, Date regDate) {
this.id = id;
this.username = username;
this.password = password;
this.phoneNo = phoneNo;
this.address = address;
this.regDate = regDate;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
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;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", phoneNo='" + phoneNo + '\'' +
", address='" + address + '\'' +
", regDate=" + regDate +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(username, user.username) &&
Objects.equals(password, user.password) &&
Objects.equals(phoneNo, user.phoneNo) &&
Objects.equals(address, user.address) &&
Objects.equals(regDate, user.regDate);
}
@Override
public int hashCode() {
return Objects.hash(id, username, password, phoneNo, address, regDate);
}
}
一定有做好注释等工作
添加c3p0需要的jar包和MySQL驱动的jar包
c3p0的配置
-
在src目录下创建c3p0-config.xml文件
-
配置 c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!-- This app is massive! --> <named-config name="mysql"> <!-- 连接MySQL基本的配置--> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mvcproject?serverTimezone=Asia/Shanghai</property> <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="user">root</property> <property name="password">root</property> <!-- 若数据库中的连接数量不足时,向数据库申请的连接数量--> <property name="acquireIncrement">5</property> <!-- 初始化数据库连接池时链接的数量--> <property name="initialPoolSize">10</property> <!-- 数据库连接池中最小的数据库链接数--> <property name="minPoolSize">5</property> <!-- 数据库连接池中最大的数据库链接数--> <property name="maxPoolSize">100</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <!-- c3p0数据库连接池可维护的Statement数量--> <property name="maxStatements">2</property> <!-- 每个连接同时可使用的Statement数量--> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config> -
在Utils包下创建JdbcUtils工具类
-
编写JdbcUtils工具类
package com.why.study2.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * jdbc工具类 * * @author why */ public class JdbcUtils { //数据库连接池,C3P0 private static DataSource dataSource = null; static {//静态代码块只会被执行一次 dataSource = new ComboPooledDataSource(); } /** * 获取到mysql的数据库连接对象 * * @return conn */ public static Connection getConnection(){ Connection conn = null; try { conn = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 通用的关闭数据库连接对象的方法 * @param conn */ public static void closeConn(Connection conn){ if (conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
创建测试类JdbcUtilsTest.java
package com.why.study2.test;
import com.why.study2.utils.JdbcUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import static org.junit.jupiter.api.Assertions.*;
class JdbcUtilsTest {
@Test
void getConnection() {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
dao层开发
创建BaseDao.java
实现基本的增删改查操作
package com.why.study2.dao;
import com.why.study2.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 这是一个dao层中的基本类,在于被具体的dao类继承,不能直接new BasesDao()来直接使用
*
* @author why
* @param <T> 针对要操作各章数据包映射到java工程里的java类
*/
public class BaseDao<T> {
QueryRunner queryRunner = new QueryRunner();
private Class<T> Clazz;
/**
* 反射拿到T.class
*/
public BaseDao() {
//用BaseDao的构造器初始化aClass属性
//拿到User类
Type superType = this.getClass().getGenericSuperclass();//getGenericSuperclass()拿到调用者的父类的类型
//拿到User.class
if (superType instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType) superType;
Type[] tarry = pt.getActualTypeArguments();//返回类型数组,其第一个元素是我们需要的T.class
if (tarry[0] instanceof Class){
Clazz = (Class<T>) tarry[0];
}
}
}
/**
* 查询数据表,取出结果sql语句的结果集的第一条数据,封装成一个类对象返回,不支持事务
* 用到dbutils工具类
* @param sql
* @param args
* @return
*/
public T get(String sql,Object... args){
Connection conn = null;
T entity = null;
//拿到conn
try {
conn = JdbcUtils.getConnection();
entity = queryRunner.query(conn,sql, new BeanHandler<T>(Clazz),args);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConn(conn);
}
return entity;
}
/**
* 重写查询数据表方法,取出结果sql语句的结果集的第一条数据,封装成一个类对象返回,支持事务
* @param sql
* @param args
* @return
*/
public T get(Connection conn,String sql,Object... args){
T entity = null;
try {
entity = queryRunner.query(conn,sql, new BeanHandler<T>(Clazz),args);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return entity;
}
/**
* 获取多条记录的通用方法
* @return
*/
List<T> getList(String sql,Object... args){
Connection conn = null;
List<T> list = null;
//拿到conn
try {
conn = JdbcUtils.getConnection();
list = queryRunner.query(conn,sql, new BeanListHandler<T>(Clazz),args);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConn(conn);
}
return list;
}
/**
* 实现insert,update,delete通用的更新方法
* @param sql
* @param args
* @return
*/
int update(String sql,Object... args){
Connection conn = null;
int rows = 0;
//拿到conn
try {
conn = JdbcUtils.getConnection();
rows = queryRunner.update(conn,sql,args);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConn(conn);
}
return rows;
}
/**
* 通用的sql语句的结果只有一个数值的类型的查询,用户个数或其他计数
* @param sql
* @param args
* @return
*/
Object getValue(String sql,Object... args){
Connection conn = null;
Object obj = null;
//拿到conn
try {
conn = JdbcUtils.getConnection();
obj = queryRunner.query(conn,sql, new ScalarHandler<>(),args);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConn(conn);
}
return obj;
}
}
创建UserDao接口
package com.why.study2.dao;
import com.why.study2.entity.User;
import java.sql.Connection;
import java.util.List;
/**
* 接口制定规则,只定义方法但不实现
* UserDao只定义与User数据表有关的方法
*
* @author why
*/
public interface UserDao {
/**
* 实现插入一条用户数据
* @param user
* @return
*/
int save(User user);
/**
* 根据用户编号删除用户
* @param id
* @return
*/
int deleteUserById(int id);
/**
* 根据id更新用户数据
* @param user
* @return
*/
int updateUserById(User user);
/**
* 根据用户id获取用户信息,支持事务
* @param id
* @return
*/
User get(int id);
/**
* 支持事务
* @param conn
* @param id
* @return
*/
User get(Connection conn,int id);
/**
* 获取所有用户数据
* @return
*/
List<User> getListAll();
/**
* 查询指定用户名的人有多少人
* @param username
* @return
*/
long getCountByName(String username);
/**
* dao层实现模糊查询的方法
* @param username
* @param address
* @param phoneNo
* @return
*/
List<User> query(String username, String address, String phoneNo);
}
UserDao实现类
package com.why.study2.dao;
import com.why.study2.entity.User;
import java.sql.Connection;
import java.util.List;
public class UserDaoImpl extends BaseDao<User> implements UserDao {
@Override
public int save(User user) {
String sql = "INSERT INTO user(`username`,`password`,`phone_no`,`address`,`reg_date`) VALUES(?,?,?,?,?);";
return super.update(sql,user.getUsername(),user.getPassword(),user.getPhoneNo(),user.getAddress(),user.getRegDate());
}
@Override
public int deleteUserById(int id) {
String sql = "delete from user where id = ?";
return super.update(sql,id);
}
@Override
public int updateUserById(User user) {
String sql = "update user set username = ?,password = ?,phone_no = ?,address = ? where id = ?";
return super.update(sql,user.getUsername(),user.getPassword(),user.getPhoneNo(),user.getId());
}
/**
* 不支持事务
* @param id
* @return
*/
@Override
public User get(int id) {
String sql = "select `id`,`username`,`password`,`phone_no` phoneNo,`address`,`reg_date` regDate FROM user WHERE `id`=?;";
User user = super.get(sql, id);
return user;
}
/**
* 支持事务
* @param conn
* @param id
* @return
*/
@Override
public User get(Connection conn, int id) {
String sql = "select `id`,`username`,`password`,`phone_no` phoneNo,`address`,`reg_date` regDate FROM user WHERE `id`=?;";
return super.get(conn,sql,id);
}
@Override
public List<User> getListAll() {
String sql = "select `id`,`username`,`password`,`phone_no` phoneNo,`address`,`reg_date` regDate from user";
return super.getList(sql);
}
@Override
public long getCountByName(String username) {
String sql = "SELECT COUNT(id) FROM user WHERE username = ?;";
return (long) super.getValue(sql,username);
}
/**
* 拼接sql语句存在sql注入的风险
* @param username
* @param address
* @param phoneNo
* @return
*/
@Override
public List<User> query(String username, String address, String phoneNo) {
System.out.println(username);
System.out.println(address);
System.out.println(phoneNo);
String sql = "SELECT id,username,password,phone_no phoneNo,address,reg_date regDate FROM user WHERE 1=1";
if (username!=null&&!"".equals(username)){
sql = sql + " AND username like '%"+username+"%'";
}
if (address!=null&&!"".equals(address)){
sql = sql + " AND address like '%"+address+"%'";
}
if (phoneNo!=null&&!"".equals(phoneNo)){
sql = sql + " AND phone_no like '%"+phoneNo+"%'";
}
System.out.println(sql);
return super.getList(sql);
}
}
创建FactoryDao
降低耦合度,dao层修改service及其他层不用修改
package com.why.study2.dao;
/**
* 工厂类
* 降低耦合度
*/
public class FactoryDao {
/**
* 返回Dao层对象
* @return
*/
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
业务(Service)层开发
创建UserService接口及其实现类
接口Userservice.java
package com.why.study2.service;
import com.why.study2.entity.User;
import java.sql.Connection;
import java.util.List;
public interface UserService {
/**
* 实现插入一条用户数据
* @param user
* @return
*/
int save(User user);
/**
* 根据用户编号删除用户
* @param id
* @return
*/
int deleteUserById(int id);
/**
* 根据id更新用户数据
* @param user
* @return
*/
int updateUserById(User user);
/**
* 根据用户id获取用户信息,支持事务
* @param id
* @return
*/
User get(int id);
/**
* 支持事务
* @param id
* @return
*/
User getTransaction(int id);
/**
* 获取所有用户数据
* @return
*/
List<User> getListAll();
/**
* 查询指定用户名的人有多少人
* @param username
* @return
*/
long getCountByName(String username);
/**
* 这是用户模糊查询的方法
* @param username
* @param address
* @param phoneNo
* @return
*/
List<User> query(String username, String address, String phoneNo);
}
实现类UserServiceImpl.java
package com.why.study2.service.impl;
import com.why.study2.dao.FactoryDao;
import com.why.study2.dao.UserDao;
import com.why.study2.dao.UserDaoImpl;
import com.why.study2.entity.User;
import com.why.study2.service.UserService;
import com.why.study2.utils.JdbcUtils;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class UserServiceImpl implements UserService {
UserDao userDao = FactoryDao.getUserDao();
@Override
public int save(User user) {
return userDao.save(user);
}
@Override
public int deleteUserById(int id) {
return userDao.deleteUserById(id);
}
@Override
public int updateUserById(User user) {
return userDao.updateUserById(user);
}
@Override
public User get(int id) {
return userDao.get(id);
}
@Override
public User getTransaction(int id) {
Connection conn = null;
User user = null;
try {
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false);
user = userDao.get(conn,id);
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
JdbcUtils.rollbackTransaction(conn);
} finally {
}
return user;
}
@Override
public List<User> getListAll() {
return userDao.getListAll();
}
@Override
public long getCountByName(String username) {
return userDao.getCountByName(username);
}
@Override
public List<User> query(String username, String address, String phoneNo) {
return userDao.query(username,address,phoneNo);
}
}
Controller层开发
实现控制转发的功能
package com.why.study2.service;
import com.why.study2.entity.User;
import java.sql.Connection;
import java.util.List;
public interface UserService {
/**
* 实现插入一条用户数据
* @param user
* @return
*/
int save(User user);
/**
* 根据用户编号删除用户
* @param id
* @return
*/
int deleteUserById(int id);
/**
* 根据id更新用户数据
* @param user
* @return
*/
int updateUserById(User user);
/**
* 根据用户id获取用户信息,支持事务
* @param id
* @return
*/
User get(int id);
/**
* 支持事务
* @param id
* @return
*/
User getTransaction(int id);
/**
* 获取所有用户数据
* @return
*/
List<User> getListAll();
/**
* 查询指定用户名的人有多少人
* @param username
* @return
*/
long getCountByName(String username);
/**
* 这是用户模糊查询的方法
* @param username
* @param address
* @param phoneNo
* @return
*/
List<User> query(String username, String address, String phoneNo);
}
View试图层开发
index.jsp
<%@ page import="java.util.Date" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="com.why.study2.entity.User" %>
<%@ page import="java.util.List" %><%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
<style type="text/css">
tr{
height: 40px;
}
td{
padding: 10px;
}
</style>
</head>
<body>
<form action="<%=request.getContextPath()%>/query.udo" method="post">
<table style="margin: 100px;padding: 50px;border: 1px #ccc solid; width: 400px">
<tr>
<td style="text-align: right">用户名:</td>
<td style="text-align: left"><input type="text" name="username"></td>
</tr>
<tr>
<td style="text-align: right">用户地址:</td>
<td style="text-align: left"><input type="text" name="address"></td>
</tr>
<tr>
<td style="text-align: right">用户电话:</td>
<td style="text-align: left"><input type="text" name="phoneNO"></td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<input type="submit" value="查询用户">
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<a href="<%=request.getContextPath()%>/add.jsp">注册新用户</a>
</td>
</tr>
</table>
</form>
<table style="margin-left: 100px; padding: 50px;" border="1" cellpadding="0" cellspacing="0">
<tr>
<td>用户ID</td>
<td>用户姓名</td>
<td>用户密码</td>
<td>用户电话</td>
<td>用户地址</td>
<td>注册日期</td>
<td>操作记录</td>
</tr>
<%
List<User> list = (List<User>) request.getAttribute("userList");
System.out.println("jsp"+list);
if (list!=null && list.size()>0){
for (User user : list) {
%>
<tr>
<td><%=user.getId()%></td>
<td><%=user.getUsername()%></td>
<td><%=user.getPassword()%></td>
<td><%=user.getPhoneNo()%></td>
<td><%=user.getAddress()%></td>
<td><%=user.getRegDate()%></td>
<td><a href="<%=request.getContextPath()%>update.udo?id=<%=user.getId()%>">编辑</a> | <a href="<%=request.getContextPath()%>delete.udo?id=<%=user.getId()%>">删除</a></td>
</tr>
<%
}
}
%>
</table>
</body>
</html>
error.jsp
<%--
Created by IntelliJ IDEA.
User: why
Date: 2020/7/22
Time: 11:52
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>error</title>
</head>
<body>
出错了,操作失败!!!
</body>
</html>
add.jsp
<%--
Created by IntelliJ IDEA.
User: why
Date: 2020/7/22
Time: 11:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>add</title>
<style type="text/css">
tr{
height: 40px;
}
td{
padding: 10px;
}
</style>
</head>
<body>
<form action="<%=request.getContextPath()%>/add.udo" method="post">
<table style="margin: 100px;padding: 50px;border: 1px #ccc solid; width: 400px">
<tr>
<td style="text-align: right">用户名:</td>
<td style="text-align: left"><input type="text" name="username"></td>
</tr>
<tr>
<td style="text-align: right">用户密码:</td>
<td style="text-align: left"><input type="text" name="password"></td>
</tr>
<tr>
<td style="text-align: right">用户地址:</td>
<td style="text-align: left"><input type="text" name="address"></td>
</tr>
<tr>
<td style="text-align: right">用户电话:</td>
<td style="text-align: left"><input type="text" name="phoneNO"></td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<input type="submit" value="注册用户">
</td>
</tr>
</table>
</form>
</body>
</html>
web.xml配置文件
Cookie
Cookie概述
会话
把同一浏览器与web服务器的一次一系列的各种交互称为会话
对会话的跟踪
Cookie机制:放在客户端
Session机制:放在服务器端
Cookie运行过程
-
客户端第一次向服务器端http请求,无cookie
-
服务端设置客户端Cookie
-
再次访问服务端器 ,带Cookie标志
-
针对性响应
服务器通过操作 Cookie类对象
对客户端Cookie进行操作。
response.addCookie(Cookie cookie)向客户端设置Cookie
request.getCookie()获取客户端提交的所有Cookie,以Cookie[]数组形式返回
Cookie属性
//cookie名
private final String name;
//cookie值
private String value;
//cookie版本
private int version = 0;
//该cookie的用处说明
private String comment;
//设置访问域名,若设置为.google.com,则所有以.goole.com结尾的域名都可访问
private String domain;
//cookie失效时间,如果为正数则Cookie在>maxAge秒之后失效,若为负数,关闭浏览器时失效
private int maxAge = -1;
//Cookie的使用路径。如果设置为/sessionWeb/在,则只有contextPath为/sessionWeb的程序可访问,若设置为/,则本域名下contextPath都可访问,注意:最后一个字符必须为/
private String path;
//cookie是否仅使用安全协议传输,默认false
private boolean secure;
这些属性都可用seter&geter方法设置和获取
JS操作Cookie的函数
通过JS控制Cookie的设置,获取和删除
<script type="text/javascript">
//js对Cookie的操作,设置,获取,删除Cookie
//设置Cookie,c_expiredays失效时间,单位:天。c_name,c_value,必填,c_expiredays选填
function setCookie(c_name,c_value,c_expiredays) {
var expires = "";
if(c_expiredays != null){
//获得系统时间
var sysDate = new Date();
//浏览器页面弹窗打印
alert(sysDate.toUTCString());
//设置时间当前时间加传送的时间
sysDate.setDate(sysDate.getDate()+c_expiredays);
alert(sysDate.toUTCString());
expires = ";expires="+sysDate.toUTCString();
alert(expires);
}
//设置cookie
document.cookie = c_name + "=" + escape(c_value) + expires;
}
alert(document.cookie);
//获取cookie,通过Cookie名获取Cookie值
function getCookie(c_name) {
//判断是否有cookie
//cookie形式 ssid = abc
if (document.cookie.length>0){
//通过子字符串的截取
//开始截取的位置索引
var start = document.cookie.indexOf(c_name + "=");
start = start + c_name.length+1;
var end = document.cookie.indexOf(";",start);
if (end == -1){
end = document.cookie.length;
}
var val = document.cookie.substring(start,end);
return unescape(val);
}
}
alert(getCookie(ssid));
//删除cookie
function deleteCookie(c_name) {
//设置Cookie失效时间是比当前时间更早的时间删除Cookie
var sysDate = new Date();
sysDate.setDate(sysDate.getDate()-1);
var time = ";expires="+sysDate.toUTCString();
var val = getCookie(c_name);
document.cookie = c_name+"="+escape(val)+time;
}
deleteCookie(ssid);
</script>
Cookie实现用户登录
Cookie可记录用户登录状态
dao层开发
/** * 实现根据用户名和密码查询用户记录的方法 * @param username * @param password * @return */ User getUserByUp(String username, String password);
@Override
public User getUserByUp(String username, String password) {
String sql = "SELECT id,username,password,phone_no phoneNo,address,reg_date regDate FROM user WHERE username=? and password=?;";
User user = super.get(sql, username, password);
return user;
}
Service开发
/** * 判断登录是否成功 * @param username * @param password * @return */ User login(String username, String password);
@Override
public User login(String username, String password) {
return userDao.getUserByUp(username,password);
}
工具类开发
CookieUtils.java
package com.why.study2.utils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.MessageDigest;
import java.util.Random;
public class CookieUtils {
/**
* 命令浏览器创建Cookie文件的方法
* @param username : 放到Cookie信息的用户名
* @param req
* @param resp : 调用Cookie方法的response对象
* @param sec : 设置Cookie失效时间,单位是秒
*/
public static void creatCookie(String username, HttpServletRequest req,HttpServletResponse resp,int sec){
//创建第一个Cookie,标记是userkey,值为username
Cookie userCookie = new Cookie("userKey",username);
//创建第二个Cookie,标记是ssid,值为加密方法,此处用ssid保存加密后的用户名,Controller取出比较验证
Cookie ssidCookie = new Cookie("ssid",md5Encrypt(username));
/**
* 设置有效期
*/
userCookie.setMaxAge(sec);
ssidCookie.setMaxAge(sec);
/**
* 调用添加Cookie
*/
resp.addCookie(userCookie);
resp.addCookie(ssidCookie);
}
/**
* 对明文字符串进行加密
* @param ss : 被加密的明文
* @return
*/
public static String md5Encrypt(String ss) {
Random random = new Random();
int i1 = random.nextInt(100);
System.out.println("随机数:"+i1);
String str1 = createStr(i1);
System.out.println("密钥:"+str1);
ss = ss==null?"":ss+str1;
//加密字典
char[] md5Digist = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] ssarr = ss.getBytes();
md.update(ssarr);//把明文放入加密类MessageDigest的对象实例中去,更新数据
byte[] digest = md.digest();//加密
int len = digest.length;
char[] str = new char[2*len];
int k = 0;//计数
for (int i = 0; i <len ; i++) {
byte b = digest[i];
//>>> 无符号位移右移n位,其余填充0
//b >>> 4 & 0xf,此处是b右移四位和0xf做与运算,运算结果是0~15
str[k++] = md5Digist[b >>> 4 & 0xf];
str[k++] = md5Digist[b & 0xf];
}
System.out.println("密文:"+new String(str));
return new String(str);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 随机生成密钥
* @param length
* @return
*/
public static String createStr(int length){
String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(62);
sb.append(str.charAt(number));
}
System.out.println(sb.toString());
return sb.toString();
}
}
Controller开发
/**
* 用户登录方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
private void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//第一步,拿到三个参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String expiredays = req.getParameter("expiredays");
Cookie[] cookies = req.getCookies();
boolean login = false;//是否登陆的标记
String account = null;//登录的账号
String ssid = null;//这是一个标记,通过cookie拿到的一个判断用户该不该登录成功的标记
if (cookies!=null && cookies.length>0){
for (Cookie cookie:
cookies) {
if (cookie.getName().equals("userKey")){
account = cookie.getValue();
}
if (cookie.getName().equals("ssid")){
ssid = cookie.getValue();
}
}
}
if (account!=null && ssid != null){
login = ssid.equals(CookieUtils.md5Encrypt(username));
System.out.println(CookieUtils.md5Encrypt(username));
}
//login时false取反变成true,表示用户未登录,第一次访问
if (!login){
//查询数据库的用户名和密码,判断用户的用户名和密码是否和输入一致
User user = userService.login(username,password);//登录成功,返回对应的User对象,登录失败,返回null
if (user !=null){
//对的,登陆成功
//设置失效时间
expiredays = expiredays == null?"":expiredays;
switch (expiredays){
case "7"://选择了记住我一周
//创建Cookie对象,设置失效时间为7天
CookieUtils.creatCookie(username,req,resp,7*24*60*60);
break;
case "30":
//创建Cookie对象,设置失效时间为30天
CookieUtils.creatCookie(username,req,resp,30*24*60*60);
break;
case "100":
//创建Cookie对象,设置没有失效时间
CookieUtils.creatCookie(username,req,resp,Integer.MAX_VALUE);
break;
default:
//默认时创建Cookie对象,设置失效时间为-1,关闭浏览器就失效
CookieUtils.creatCookie(username,req,resp,-1);
break;
}
//登录成功,准许客户进入到main.jsp页面
req.getRequestDispatcher("/main.jsp").forward(req,resp);
}else {
req.setAttribute("note","用户名或密码错误!!!");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
}else {
req.getRequestDispatcher("/main.jsp").forward(req,resp);
}
}
}
View层开发
<%--
Created by IntelliJ IDEA.
User: why
Date: 2020/7/23
Time: 12:07
To change this template use File | Settings | File Templates.
--%>
<%
