真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Spring3.0第三講:Spring實(shí)現(xiàn)簡(jiǎn)單的登錄

   學(xué)習(xí)Spring這些技術(shù)性框架,光掌握理論知識(shí)是遠(yuǎn)遠(yuǎn)不夠了,我們要懂得學(xué)以致用,用鍵盤(pán)將學(xué)到的敲出來(lái),在正確與錯(cuò)誤中尋找Spring的用法。

創(chuàng)新互聯(lián)建站主營(yíng)金溪網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都app開(kāi)發(fā),金溪h5微信小程序搭建,金溪網(wǎng)站營(yíng)銷(xiāo)推廣歡迎金溪等地區(qū)企業(yè)咨詢(xún)

      為了給讀者一個(gè)直觀的概念,這里我用Spring搭建一個(gè)簡(jiǎn)單的登錄,可以讓你很快的了解Spring在持久層、業(yè)務(wù)層、表現(xiàn)層是怎么運(yùn)作的,這樣后面我們分模塊講解的時(shí)候,讀者也能很快的知道。

     本文所用工具為Eclipse IDE,數(shù)據(jù)庫(kù)為Oracle 11g。

     首先我們來(lái)了解登錄這個(gè)功能,用戶(hù)訪(fǎng)問(wèn)登錄頁(yè)面,輸入賬號(hào)和密碼,點(diǎn)擊登錄,后臺(tái)驗(yàn)證是否有賬號(hào)和密碼匹配,如果匹配成功,則跳到歡迎頁(yè)面,并顯示用戶(hù)積分,如果登錄失敗則返回登錄頁(yè)面,并提示登錄失敗信息。

    簡(jiǎn)化圖:

    Spring3.0第三講:Spring實(shí)現(xiàn)簡(jiǎn)單的登錄

 有經(jīng)驗(yàn)的程序員知道在開(kāi)發(fā)之前都會(huì)先寫(xiě)開(kāi)發(fā)設(shè)計(jì)或者畫(huà)類(lèi)圖,這里面筆者也從開(kāi)發(fā)設(shè)計(jì)開(kāi)始,針對(duì)登錄的全過(guò)程先設(shè)計(jì)好再開(kāi)發(fā),畢竟磨刀不誤砍材功。

    上面是登錄功能設(shè)計(jì)的全部過(guò)程大致描述一下:

Spring3.0第三講:Spring實(shí)現(xiàn)簡(jiǎn)單的登錄

1.首先訪(fǎng)問(wèn)login.jsp,返回可輸入用戶(hù)賬號(hào)以及密碼的表單登錄頁(yè)面

2.用戶(hù)在登錄頁(yè)面輸入賬號(hào)、密碼,提交表單到服務(wù)器,Spring根據(jù)配置調(diào)用LoginController控制器響應(yīng)請(qǐng)求。

3.LoginController調(diào)用LoginService/isExistUser方法,根據(jù)傳遞的用戶(hù)、密碼參數(shù)查詢(xún)是否存在用戶(hù),LoginService內(nèi)部通過(guò)持久層LoginDao與數(shù)據(jù)進(jìn)行交互。

4.如果匹配不到用戶(hù),則返回Login.jsp,并返回提示信息,如果匹配成功,則進(jìn)入下一步。

5.LoginController調(diào)用LoginService/findUserByUsername獲取當(dāng)前登錄人的實(shí)體,設(shè)置當(dāng)前登錄時(shí)間以及積分更新后的值。

6.LoginController調(diào)用LoginService/loginsuccess()方法,進(jìn)行登錄成功后的業(yè)務(wù)處理,首先更新用戶(hù)信息,以及創(chuàng)建LoginInfo日志對(duì)象并插入數(shù)據(jù)庫(kù)。

7.重定向歡迎頁(yè)面welcome.jsp頁(yè)面,并返回響應(yīng)。

環(huán)境準(zhǔn)備:

1.表創(chuàng)建

create table TB_USER   --用戶(hù)表
(
  userid          VARCHAR2(20),
  username        VARCHAR2(20),
  credits         NUMBER,
  password        VARCHAR2(100),
  last_login_time DATE,
  last_login_ip   VARCHAR2(30)
)
create table TB_LOGIN_LOG --用戶(hù)登錄日志
(
  login_id      VARCHAR2(20),
  login_user_id VARCHAR2(20),
  ip            VARCHAR2(20),
  login_time    DATE
)
--插入一條用戶(hù)
insert into tb_user (USERID, USERNAME, CREDITS, PASSWORD, LAST_LOGIN_TIME, LAST_LOGIN_IP)
values ('zhangsan', '張三', 0, '123456', to_date('06-07-2016 09:10:39', 'dd-mm-yyyy hh34:mi:ss'), '0:0:0:0:0:0:0:1');

2.建立工程

Spring3.0第三講:Spring實(shí)現(xiàn)簡(jiǎn)單的登錄

    良好的包分類(lèi)以及分層會(huì)給維護(hù)以及其他開(kāi)發(fā)帶來(lái)的很大的好處,一般企業(yè)項(xiàng)目中包的分類(lèi)還應(yīng)該按項(xiàng)目模塊分,本文的項(xiàng)目較簡(jiǎn)單,因此分類(lèi)就簡(jiǎn)單化,同時(shí)對(duì)于Spring 的配置文件一般都會(huì)有文件夾存放,這里我們就不詳細(xì)說(shuō)明,相信讀者在工作中看到的項(xiàng)目大多數(shù)都是結(jié)構(gòu)良好的。

   關(guān)于Spring3.0相關(guān)jar,這里面讀者可以自己去下載。

3.創(chuàng)建實(shí)體類(lèi)

   我們可以認(rèn)為實(shí)體類(lèi)是貫穿業(yè)務(wù)層、持久層、表現(xiàn)層的一條線(xiàn),一個(gè)功能模塊往往是圍繞一個(gè)實(shí)體類(lèi),業(yè)務(wù)層修改實(shí)體類(lèi)狀態(tài),持久層將實(shí)體類(lèi)存儲(chǔ)到數(shù)據(jù)庫(kù),表現(xiàn)層展現(xiàn)實(shí)體類(lèi)的狀態(tài),可見(jiàn)實(shí)體類(lèi)的重要性。

public class User {
	 private String userid;//用戶(hù)ID
	 private String username;//用戶(hù)姓名
	 private Integer credits;//積分
	 private String password;//密碼
	 private Date lastlogintime;//最后登錄時(shí)間
	 private String loginip;//最后登錄ip
	 }
public class LoginInfo {
    private String loginid;//登錄主鍵
    private String loginuserid;//登錄人ID
    private String loginip;//登錄IP
    private Date logintime;//登錄時(shí)間
    }
......省略get、set方法

4.持久層LoginDao與LoginLogDao

 我們先看看關(guān)于操作User的DAO,主要包括3個(gè)方法

1.getUserCount(),返回結(jié)果為×××,如果返回1,則表示用戶(hù)、密碼匹配正確,返回0則表示用戶(hù)、密碼匹配錯(cuò)誤,實(shí)際中這里存在密碼加密解密功能,這里我們簡(jiǎn)單化。

2.findUserByUsername(),根據(jù)用戶(hù)賬號(hào)獲取User實(shí)體。

3.updateUserInfo(),更新用戶(hù)最后登錄時(shí)間、 積分以及用戶(hù)IP.

import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;
import domain.User;
@Repository //通過(guò)Spring注解定義一個(gè)Dao
public class LoginDao {
    
     @Autowired//自動(dòng)注入id為JdbcTemplate的bean
     private JdbcTemplate jdbcTemplate; 
     /**
      * 
       * @author zangyn
       * @date 2016-8-19 下午1:54:16
       * @Title: getUserCount
       * @Description: 根據(jù)賬號(hào)、密碼匹配是否存在
       * @return int    返回類(lèi)型
       * @throws
      */
     public int getUserCount(String username,String password){
    	 String sql="SELECT COUNT(*) FROM TB_USER U WHERE U.USERID=? AND U.PASSWORD=?";
		 int count=jdbcTemplate.queryForInt(sql,new Object[]{username,password});
    	 return count;
	}
	/**
	 * 
	  * @author zangyn
	  * @date 2016-8-19 下午1:54:43
	  * @Title: findUserByUsername
	  * @Description: 根據(jù)Userid查詢(xún)是否存在該User
	  * @return User    返回類(lèi)型
	  * @throws
	 */
	public User findUserByUsername(String userid){
		String sql="SELECT * FROM TB_USER U WHERE U.USERID=?";
		final User u=new User();
		jdbcTemplate.query(sql, new Object[]{userid}, new RowCallbackHandler() {
			
			@Override
			public void proce***ow(ResultSet rs) throws SQLException {
				u.setUserid(rs.getString("userid"));
				u.setUsername(rs.getString("username"));
			   	u.setCredits(rs.getInt("credits"));
			}
		});
		return u;
	}
	/**
	 * 
	  * @author zangyn
	  * @date 2016-8-19 下午1:55:28
	  * @Title: updateUserInfo
	  * @Description: 更新用戶(hù)相關(guān)信息
	  * @return void    返回類(lèi)型
	  * @throws
	 */
	
	public void updateUserInfo(User user){
		String sql="UPDATE TB_USER U SET U.LAST_LOGIN_TIME=?,U.LAST_LOGIN_IP=?,U.CREDITS=? WHERE U.USERID=?";
		jdbcTemplate.update(sql, new Object[]{user.getLastlogintime(),user.getLoginip(),user.getCredits(),user.getUserid()});
	}
}

   Spring2.5以后,可以使用注解的方式定義Bean,相比較XML配置,注解配置簡(jiǎn)單太多,所以我們盡量要以注解為主進(jìn)行Bean配置。

這里我們用@Repository定義了Dao bean的配置,使用 @Autowired將容器的Bean注入進(jìn)來(lái)。

  從上面可以看到關(guān)于數(shù)據(jù)庫(kù)操作,我們引入了Spring JdbcTemplate,用過(guò)原始JDBC的都知道,在執(zhí)行數(shù)據(jù)庫(kù)操作之前都需要經(jīng)過(guò):獲取連接>創(chuàng)建Statement>執(zhí)行數(shù)據(jù)庫(kù)操作>獲取結(jié)果>關(guān)閉Statement>關(guān)閉結(jié)果集>關(guān)閉連接,同時(shí)我們還要關(guān)注異常的處理,每次執(zhí)行sql,我們的1/3代碼都重復(fù)的寫(xiě)以上的代碼,對(duì)于以上樣板式的代碼,Spring JDBC進(jìn)行了薄層的封裝,將樣板式的代碼進(jìn)行了封裝,用戶(hù)只需要編寫(xiě)那些必不可少的代碼。

關(guān)于拼寫(xiě)SQL注意:在拼寫(xiě)較長(zhǎng)的sql時(shí),我們經(jīng)常需要換行,由于上下行最終會(huì)轉(zhuǎn)換為一個(gè)sql,這時(shí)候如果在每行的末尾沒(méi)有空格,就會(huì)存在連在一起的情況,因此,良好的拼寫(xiě)SQL方法是在每行開(kāi)始和結(jié)尾都打一個(gè)空格。

 關(guān)于JdbcTemplate各種方法運(yùn)用,我會(huì)在后面一篇詳細(xì)介紹。

 LoginLogDao只有一個(gè)存放日志記錄的方法,代碼如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import domain.LoginInfo;

@Repository //通過(guò)Spring注解定義一個(gè)Dao
public class LoginLogDao {
	
	@Autowired//自動(dòng)注入id為JdbcTemplate的bean
     private JdbcTemplate jdbcTemplate;
	 public void insertLoginfo(LoginInfo info){
		 String sql="INSERT INTO TB_LOGIN_INFO(LOGIN_ID,LOGIN_USER_ID,IP,LOGIN_TIME) VALUES(login_info_seq.nextval,?,?,?)";
		 Object[] obj=new Object[]{info.getLoginuserid(),info.getLoginip(),info.getLogintime()};
		 jdbcTemplate.update(sql, obj);
	 }
}

5.數(shù)據(jù)源配置以及Spring 加載Dao

在src下創(chuàng)建一個(gè)名為applicationContext.xml的文件,配置文件內(nèi)容如下:



	



 
        
          
          
          
     
     
    
		
	

Spring的掃描指定包下的類(lèi),這樣@Repository、@Autowired注解才能起作用。

關(guān)于數(shù)據(jù)源配置這里只存在不同的配置源問(wèn)題,關(guān)于為什么要這么配置,只能說(shuō)是JDBC規(guī)范要求。

jdbcTemplate這個(gè)bean將dataSource注入到JdbcTemplate,然后JdbcTemplate Bean通過(guò)@Autowired注入到LoginLogDao和LoginDao中。

6. 服務(wù)層 LoginService

    loginservice接口有三個(gè)方法:isExistUser用于驗(yàn)證賬號(hào)、密碼正確性、findUserByUsername用于根據(jù)用戶(hù)賬號(hào)加載User實(shí)體、loginSuccess用于登錄成功進(jìn)行積分變更、日志插入操作,這里存在事務(wù)操作,更新tb_user并插入tb_login_info,但是我們卻沒(méi)看到關(guān)于事務(wù)控制的代碼,Spring的一大優(yōu)點(diǎn)就是將事務(wù)從代碼中解放出來(lái),下面我會(huì)講解關(guān)于Spring處理事務(wù)能力。

   

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import dao.LoginDao;
import dao.LoginLogDao;
import domain.LoginInfo;
import domain.User;

@Service //將LoginServcie標(biāo)注為一個(gè)服務(wù)層Bean
public class LoginService {
	@Autowired
	private LoginDao logindao;
	@Autowired
	private LoginLogDao loginlogdao;
	
  public boolean isExistUser(String userid,String password){
	  int count=logindao.getUserCount(userid, password);
	  return count>0;
  }
  public User findUserByUsername(String userid){
	  return logindao.findUserByUsername(userid);
  } 
  public void loginSuccess(User u){
	  u.setCredits(u.getCredits()+5);
	  LoginInfo info=new LoginInfo();
	  info.setLoginuserid(u.getUserid());
	  info.setLogintime(u.getLastlogintime());
	  info.setLoginip(u.getLoginip());
	  loginlogdao.insertLoginfo(info);
	  logindao.updateUserInfo(u);
  }
}

7.Spring加載Service

   Spring的事務(wù)雖然不用出現(xiàn)在代碼中,但是我們需要告訴Spring哪些業(yè)務(wù)類(lèi)需要工作于事務(wù)環(huán)境以及事務(wù)的規(guī)則等內(nèi)容,讓Spring根據(jù)這些信息自動(dòng)為目標(biāo)業(yè)務(wù)類(lèi)添加事務(wù)管理功能。

 



	
	
	
    
    
     
        
          
          
          
     
     
    
		
	
	
	
    
    
    
    
        
                
       
    
    
        
            
        
    

關(guān)于業(yè)務(wù)層和配置已經(jīng)完成,我們先單元測(cè)試一下。

8.單元測(cè)試

   Spring 3.0的測(cè)試框架可以和Junit4整合,通過(guò)@RunWith可以指定SpringJUnit4Cla***unner測(cè)試運(yùn)行器,該運(yùn)行器是Spring提供的,可以將Spring容器和Junit4測(cè)試框架結(jié)合。@ContextConfiguration也是Spring提供的注解,用于指定Spring配置文件。@Test用于將方法標(biāo)注為測(cè)試方法,

import static org.junit.Assert.*;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4Cla***unner;
import domain.User;
import service.LoginService;

@RunWith(SpringJUnit4Cla***unner.class)//基于JUnit4的Spring測(cè)試框架
@ContextConfiguration(locations={"classpath:applicationContext.xml"})//啟動(dòng)spring容器
public class TestUserService {
	@Autowired//注入spring容器bean
	private LoginService loginservice;
	@Test
	public void isExistUser() {
		boolean a1=loginservice.isExistUser("zhangsan", "123456");
		boolean a2=loginservice.isExistUser("zhangsan", "1");
		assertTrue(a1);
		assertTrue(!a2);
	}
	@Test
	public void findUserbyUsername() {
		User u=loginservice.findUserByUsername("zhangsan");
		assertEquals(u.getUserid(), "zhangsan");
	}
	
	@Test
	public void loginSuccess(){
		User u=new User();
		u.setUserid("zhangsan");
		u.setCredits(0);
		u.setLoginip("127.0.0.1");
		u.setLastlogintime(new Date());
		loginservice.loginSuccess(u);
	}
}

9.配置SpringMVC

  業(yè)務(wù)層以及持久層已經(jīng)完成,現(xiàn)在我們需要用SpringMVC將展現(xiàn)層加入個(gè)整個(gè)功能里。首先對(duì)web.xml進(jìn)行配置





contextConfigLocation
classpath:applicationContext.xml



	org.springframework.web.context.ContextLoaderListener



Spring
org.springframework.web.servlet.DispatcherServlet
    
        contextConfigLocation
        classpath:Spring-servlet.xml
    
 1  



Spring
*.html

   web容器通過(guò)上下文參數(shù)指定Spring配置文件,多個(gè)配置文件可用逗號(hào)分開(kāi),然后web容器在啟動(dòng)的時(shí)候會(huì)自動(dòng)啟動(dòng)監(jiān)聽(tīng)器ContextLoaderListener,該監(jiān)聽(tīng)器的作用是獲取Spring配置文件并啟動(dòng)Spring容器,注意將log4j.properties放在類(lèi)路徑下,以便日志引擎生效。

   SpringMVC也是通過(guò)截獲URL請(qǐng)求,然后進(jìn)行相關(guān)處理。

   這里面注意SpringMVC也有個(gè)配置文件,該配置文件的文件與這里定義的Servlet名有一個(gè)契約,即

采用-servlet.xml,在這里Servlet的名稱(chēng)為Spring,意思是/WEB-INF下必須有個(gè)Spring-servlet.xml的配置文件,這個(gè)配置文件無(wú)需通過(guò)web.xml的上下文進(jìn)行配置,SpringMVC的Servlet會(huì)自動(dòng)將Spring-servlet.xml與其他配置文件拼裝。

 

        contextConfigLocation

        classpath:Spring-servlet.xml

   

這里如果配置這個(gè)參數(shù)則配置文件就不會(huì)去執(zhí)行上面的契約去查找Spring-servlet,會(huì)根據(jù)我們自己配置的文件查找。

   Servlet的URL路徑進(jìn)行定義我們讓所有后綴以.html的URL都能被Spring Servlet截獲,然后轉(zhuǎn)給SpringMVC進(jìn)行處理,請(qǐng)求被SpringMVC接受后,首先根據(jù)URL找到目標(biāo)的處理控制器,并將請(qǐng)求參數(shù)封裝成一個(gè)“命令”對(duì)象一起傳給控制器處理,控制器調(diào)用Spring 的業(yè)務(wù)Bean進(jìn)行處理并返回視圖。

10.控制器類(lèi)LoginController

  LoginController負(fù)責(zé)處理登錄請(qǐng)求,完成登錄業(yè)務(wù),根據(jù)登錄結(jié)果返回不同頁(yè)面。

import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import domain.LoginCommand;
import domain.User;
import service.LoginService;

@Controller
public class LoginController {

	@Autowired
	private LoginService loginservice;
	
	@RequestMapping(value="/index.html")
	public String loginPage(){
		return "login";
	}
	@RequestMapping(value="/loginCheck.html")
	public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
		boolean isValid=loginservice.isExistUser(loginCommand.getUserid(), loginCommand.getPassword());
		if(!isValid){
			return  new ModelAndView("login","error","用戶(hù)或密碼錯(cuò)誤");
		}else{
			User user=loginservice.findUserByUsername(loginCommand.getUserid());
			user.setLoginip(request.getRemoteAddr());
			user.setLastlogintime(new Date());
			request.getSession().setAttribute("user", user);
			loginservice.loginSuccess(user);
			return new ModelAndView("welcome");
		}
	}
}

@Controller將LoginController標(biāo)注為SpringMVC控制器,處理HTTP請(qǐng)求,一個(gè)控制器包含多個(gè)HTTP請(qǐng)求路徑的處理方法,通過(guò)@RequestMapping指定方法映射請(qǐng)求路徑。

請(qǐng)求參數(shù)會(huì)根據(jù)參數(shù)名稱(chēng)默認(rèn)契約自動(dòng)綁定到響應(yīng)方法的入?yún)⒅?,在loginCheck(HttpServletRequest request,LoginCommand loginCommand),請(qǐng)求參數(shù)會(huì)根據(jù)名稱(chēng)匹配綁定到loginCommand中。

public class LoginCommand {

	private String userid;//用戶(hù)id
	private String password;//用戶(hù)密碼
	省略get/set
	}

請(qǐng)求方法可以返回ModelAndView或者字符串,SpringMVC會(huì)解析并自動(dòng)轉(zhuǎn)向目標(biāo)響應(yīng)頁(yè)面。關(guān)于ModelAndView讀者只需知道它目前代表一種視圖就行,后面會(huì)解釋。

現(xiàn)在需要知道ModelAndView返回的兩種形式,ModelAndView("login","error","用戶(hù)或密碼錯(cuò)誤")和ModelAndView("main"),第一個(gè)參數(shù)代表視圖的邏輯名,第二個(gè)以及第三個(gè)代表數(shù)據(jù)模型名稱(chēng)和數(shù)據(jù)模型對(duì)象,數(shù)據(jù)模型對(duì)象將以數(shù)據(jù)模型名稱(chēng)為參數(shù)名放置到request屬性中。

SpringMVC的配置文件Spring-servlet.xml



	
	
	
	

上面SpringMVC通過(guò)配置來(lái)解析ModelAndView,Spring有許多解析ModelAndView的方式,這里我們用InternalResourceViewResolver,它通過(guò)添加前后綴方式來(lái)解析。如ModelAndView("welcome"),將解析為/WEB-INF/login/welcome.jsp

11.JSP頁(yè)面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>




論壇登錄




" method="post">

					  	
						
						
						
					


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>




論壇主頁(yè)


${user.username},歡迎你進(jìn)入本論壇,你的積分為${user.credits}.

這里我引入c標(biāo)簽,需要引入兩個(gè)jar包。

剩下的可以直接部署了,然后訪(fǎng)問(wèn)http://localhost:8088/項(xiàng)目部署名稱(chēng)/,輸入zhangsan、123456即可登錄成功。


名稱(chēng)欄目:Spring3.0第三講:Spring實(shí)現(xiàn)簡(jiǎn)單的登錄
網(wǎng)頁(yè)URL:http://weahome.cn/article/gpssgo.html

其他資訊

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部