我们通过一个实现登陆的小案例来演示
新建项目首页index.html,并布局一个帐号密码表单内容
<!--action的路径直接指向servlet的访问入口-->
<form action="/项目名/loginServlet" method="post">
<input name="loginname" type="text"/>
<input name="loginpass" type="password"/>
<button type="submit">登录</button>
</form>
接
Servlet可以帮我们从页面的请求中获取信息,通过视图层的name,接收视图层传来的数据。
接单独信息:调用service中的request参数的getParameter()方法。
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String loginname = request.getParameter("loginname");
String loginpass = request.getParameter("loginpass");
System.out.println(loginname + " : " + loginpass);
}
}
接多组信息:调用service中的request参数的getParameterValues()方法。
String[] hobby = request.getParameterValues("index所命名的值");
接中文信息:默认无法接收中文信息。
request.setCharacterEncoding("UTF-8");//设置"请求"按照utf-8模式转码
response.setContentType("text/html;charset=utf-8");//设置"响应"按照utf-8编码向页面输出
String loginname = request.getParameter("loginname");
System.out.println(loginname);
调
这里我用封装好的jdbc来实现从数据库取值
创建service层接口LoginService
public interface LoginService {
boolean login(String loginname,String loginpass);
}
创建service层实现类LoginServiceImpl
public class LoginServiceImpl implements LoginService{
@Override
public boolean login(String loginname, String loginpass) {
return false;
}
}
创建dao层接口LoginDao
public interface LoginDao {
Map<String,Object> login(String loginname);
}
创建dao层实现类LoginDaoImpl
@Override
public Map<String, Object> login(String loginname) {
return null;
}
编写数据层dao
在dao数据层中实例化jdbc对象,调用jdbc的对应方法,完成数据持久化过程
public class LoginDaoImpl implements LoginDao {
private JDBC jdbc = JDBCFactory.getJDBC();// 实例化jdbc对象
@Override
public Map<String, Object> login(String loginname) {
String sql = "select * from t_login where loginname = ?";
return jdbc.retrieveOne(sql, loginname);
}
}
编写业务层service
在service业务层中实例化dao层对象,调用dao层的对应方法
public class LoginServiceImpl implements LoginService{
private LoginDao dao = new LoginDaoImpl();// 实例化dao层对象
@Override
public boolean login(String loginname, String loginpass) {
boolean result = false;// 定义初始结果
if(loginname !=null && loginpass != null) {// 账密非空保护
Map<String, Object> resultMap = dao.login(loginname);// 调用dao层方法
if(!resultMap.isEmpty()) {// 帐号正确
String loginpassFromDB = (String)resultMap.get("loginpass");// 比对密码
if(loginpassFromDB==null){
loginpassFromDB="";
}
if(loginpass.equals(loginpassFromDB)) {// 密码正确
result = true;// 更改结果
}
}
}
return result;// 返回最终结果
}
}
补充控制层servlet
在servlet控制层中实例化service层对象,然后调用service层的对应方法
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet{
private LoginService service = new LoginServiceImpl();// 实例化service层对象
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");//设置"请求"按照utf-8模式转码
response.setContentType("text/html;charset=utf-8");//设置"响应"按照utf-8编码向页面输出
String loginname = request.getParameter("loginname");
String loginpass = request.getParameter("loginpass");
// 调用service层的方法
boolean result = service.login(loginname,loginpass);
System.out.println(result);
}
}
存
如果你想在页面上展示某些内容,那么就需要把这些内容存起来,否则可以跳过"存"的步骤。
存有四种方式
1 使用request存
javax.servlet.http.HttpServletRequest:生命周期为一次转页
if(result){
//1.request : 一次请求
request.setAttribute("loginname",loginname);
String loginnameFromRequest = (String)request.getAttribute("loginname");
System.out.println("loginnameFromRequest:" + loginnameFromRequest);
}
tips:页面端使用 r e q u e s t S c o p e . l o g i n n a m e 或 {requestScope.loginname}或 requestScope.loginname或{loginname}取值。
使用session存
javax.servlet.http.HttpSession:声明周期为一次会话(浏览器开启到关闭)
if(result){
//2.session: 浏览器只要不关,值就一直存在
HttpSession session = request.getSession();
session.setAttribute("loginname",loginname);
String loginnameFromSession = (String)session.getAttribute("loginname");
System.out.println("loginnameFromSession:" + loginnameFromSession);
}
tips:页面端使用${sessionScope.loginname}取值。
使用application存
javax.servlet.ServletContext:生命周期为一次应用(服务器开启到关闭)
if(result){
//3.application:服务器只要不关,值就一直存在
ServletContext application = request.getSession().getServletContext()
application.setAttribute("loginname",loginname);
String loginnameFromApplication = (String)application.getAttribute("loginname");
System.out.println("loginnameFromApplication:" + loginnameFromApplication);
}
tips:页面端使用${applicationScope.loginname}取值。
使用cookie存值
javax.servlet.http.Cookie:存值期限自定义,适用于HTML页面端取值方式
Cookie c_loginname = new Cookie("loginname",loginname);// 设置cookie
c_loginname.setMaxAge(7*24*3600);// 存7天,如果不设置时间,或者设置为0,cookie不存在
response.addCookie(c_loginname);// 回写到客户端
Cookie[] cookies = request.getCookies();// 获取所有cookies
for(int i=0, j=cookies.length; i<j; i++){// 遍历cookies
if("loginname".equals(cookies[i].getName())){// 判断名字是否为loginname
System.out.println(cookies[i].getValue());// 打印对应的值
}
}
cookie和session存值的对比分析
cookie是保留在客户端,session保留在服务端。
cookie安全性低。
cookie通过网络在客户端与服务器端传输,session保留在服务器端,不需要传输。
以20分钟为例,cookie生命周期是累积的,从创建时候就开始计时,20分钟后失效。session的生命周期是间隔的,从创建时开始计时,如果在20分钟内没有访问过session,session失效,如果20分钟内,比如第19分钟访问了session,那么它的生命周期将重新开启一个20分钟。
关机会造成session生命终结,但是对cookie没有任何影响。
转
转就是值对页面的一个响应。
请求转发
一个请求发给服务器,服务器帮我们执行任务,这就是请求转发的工作模式。
请求转发直接从webroot/webContext下粘贴路径,页面转发时地址栏不会发生变化。
if(result){
// 请求转发
request.getRequestDispatcher("/html/main.html").forward(req, resp);
}
重定向
一个请求发给服务器,服务器不帮我们执行,而是返回一个,目标地址,我们自己按照目标地址去执行任务,这就是重定向的工作模式。
重定向的路径前需要补充项目发布名,页面转发时地址栏会发生改变。
我们一般只有在失败的跳转页面和防止刷新的页面,才会用到重定向。
if(result){
// 告诉用户失败了
// 跳转页面,跳回index.jsp
// 重定向更适用于失败的跳转
response.sendRedirect(request.getContextPath() + "/index.html");
}
WEB-INF下的重定向
当我们想要跳转的jsp文件在WEB-INF下,请求转发并无影响,但重定向会失败,这时我们可以通过编写WEB-INF下的web.xml进行映射。
例如有个JSP文件/WEB-INF/html/my.html,那么web.xml可以如下编写
<servlet>
<servlet-name>my</servlet-name>
<jsp-file>/WEB-INF/html/my.html</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>my</servlet-name>
<url-pattern>/myfile</url-pattern>
</servlet-mapping>
然后可以通过重定向[response.sendRedirect(request.getContextPath()+"/myfile")]来达到访问/WEB-INF/jsp/my.jsp的目的。