BOS2
内容(1)在业务中会重复性的增删改查的操作做Dao的封装来简化,Dao层的开发。
(2)Spring Data JPA :主要针对的就是Spring唯一没有简化到的业务逻辑代码,至此,开发者练仅剩的实现持久层业务逻辑的工作都省了,唯一要做到,就只是声明持久层的接口,其他都交给Spring Data JPA来帮你完成!
(3)建表--》实体类 封装dao---->spring data jpa Respository接口(重点) 业务层封装
(4)Action封装 共性:接收客户端请求,封装数据到Model 需要继承和实现,重复性代码。 操作request和response都封装到BaseAction 操作 请求数据-request.getParameter/values
(5)封装好之后实现用户的登录,封装是为了后面的代码简化,不会太繁琐。
1、使用PD根据大纲绘制用户表
建模工具来设计表。
PD的作用,通过建模工具 绘制表设计---->根据不同数据库生成不同脚本!mysql--->oracle
PD是绘制表设计图例,xxx.pdm文件--->pd---->生成不同数据库脚本。
安装好之后,new一个Physical Data Model:物理数据模型。这个模型就会建立图例生成底层的sql。
密码用MD5加密,一般是32位。
tools--->PDM Generation Options可以切换成oracle数据库。
但是需要去掉引号,
mysql-->source 拖入文件也可以执行.sql文件。
2、通过表反向生成实体类
<!-- hibernate-tools 反向生成实体类 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-tools</artifactId> </dependency>
<plugins> <!--通过命令直接生成实体类 和注解或配置文件 User.hbm.xml--> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <configuration> <components> <component> <!-- 命令 可以生成实体类对应映射文件 User.hbm.xml --> <name>hbm2hbmxml</name> <implementation>jdbcconfiguration</implementation> <!-- 文件输出位置 --> <outputDirectory>target/generated-resources/hibernate</outputDirectory> </component> <component> <!-- 命令 生成实体类的 但是不会生成注解的 --> <name>hbm2java</name> <implementation>jdbcconfiguration</implementation> <outputDirectory>target/generated-sources/hibernate</outputDirectory> </component> </components> <componentProperties> <!-- 该配置文件必须存放该目录下 作用: 根据表生成实体类 定义实体类生成规范 --> <revengfile>src/main/resources/reveng.xml</revengfile> <!-- hibernate.properties 文件 插件需要连接数据库 配置信息 --> <propertyfile>src/main/resources/hibernate.properties</propertyfile> <!-- 生成实体类默认生成包名 --> <packagename>cn.itcast.mavenbos.domain</packagename> <jdk5>true</jdk5> <!-- true 生成注解 /false 没有注解 --> <ejb3>true</ejb3> </componentProperties> </configuration> </plugin>
Domain模块
插件已经安装成功
将需要的配置文件拷贝到src/main/resource目录
Reveng.xml定义实体类生成规则,表名的定义 主键策略生成 字段属性名定义 长度
Hibernate.properties文件 插件连接数据库信息
(1)Hibernate.properties
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql:///zero_bos
hibernate.connection.username=root
hibernate.connection.password=123
(2)reveng.xml可以先不定义
(3)独立执行bos-domain hibernate3:hbm2java 命令;
项目右键----->run as----->Maven build---->Goals: hibernate3:hbm2java ------>run
定义reveng.xml 文件 定义实体类生成规则
<!-- match-table:访问表的 (代表这个表能够被找到).对于数据库zero_bos下面t_user表定义实体类生成规则 --> <schema-selection match-table="t_user" match-catalog="zero_bos" /> <!-- 实体类生成规则定义 --> <table name="t_user" catalog="zero_bos" class="com.zero.bos.domain.user.User"> <primary-key> <!-- uuid主键(字符) identity:主键自增长--> <generator class="uuid"></generator> </primary-key> </table> </hibernate-reverse-engineering>
配置好reveng.xml之后再重新运行一下。
就会生成主键为uuid的User类。
@GenericGenerator(name="generator", strategy="uuid")@Id @GeneratedValue(generator="generator") @Column(name="ID", unique=true, nullable=false, length=32) public String getId() { return this.id; }
3、Spring data jpa学习
Maven配置 在domain.xml已经引入相关spring data jpa
模块开始配置 applicationContext-domain.xml来进行domain与spring的整合。
(1)首先domain需要一个注册文件来注册实体类
entityManagerFactory管理实体类
在resources中的
hibernate.properties是反向代理工具用来通过数据库表来生成实体类的
jdbc.properties是数据库连接池使用的外部配置文件
配置文件需要写入(1)数据库连接池(2)entityManagerFactory工厂类型sessionFactory
context配置文件需要:(1)引入数据库连接池外部配置文件(2)包扫码:扫码注解(类似@Controller)(3)配置连接池信息(4)EntityManagerFactory
全部配置文件:
applicationContest-domian.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <!-- 数据库 连接池 jpa EntityManagerFactory 连接池需要的外部配置文件 --> <context:property-placeholder location="classpath:jdbc.properties" /> <!-- 开始Spring注解@Controller @Service @Respository @Autowired @Scope --> <context:component-scan base-package="com.zero.bos"></context:component-scan> <!-- 配置连接池信息 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 配置 连接数据库参数 c3p0 连接池 --> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- sessionFactory 类似EntityMangerFactory spring data jpa 配置学习 参照官方文档 EntityManagerFacotry --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描实体类 包以及子包 --> <property name="packagesToScan" value="com.zero.bos.domain" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL" /> <!-- 自动建表 --> <property name="generateDdl" value="true" /> <!-- 方言 --> <property name="databasePlatform" value="${jdbc.dialect}"></property> <!-- 显示sql --> <property name="showSql" value="true"></property> </bean> </property> </bean> </beans>
jdbc.properties文件内容:
jdbc.url=jdbc:mysql:///zero_bos
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123
jdbc.dialect=org.hibernate.dialect.MySQL5Dialect
测试:(1)main方法进行加载applicationContext-domain.xml就自动建表
(2)启动tomcat,也会自动加载,但是因为tomcat是首先加载web.xml的所以,需要在web.xml中添加applicationContext-domain.xml
<!-- spring配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml,classpath:applicationContext-domain.xml</param-value> </context-param>
run as---->tomcat:run。查看数据库是否有自动建表即可。(如果没有检查包扫码的路径是否正确)
4、Spring Data Jpa配置说明
接口需要能够被spring data jpa 识别,否则无法通过接口生成实现类。
不需要程序员进行接口实现类的编写,它会自动生成实体类。
官方标准
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <jpa:repositories base-package="com.acme.repositories" /> </beans>
(1)引入jpa相关的三个名称空间就可以使用
(2)配置Spring Data Jpa 接口扫码
<!-- Spring data jpa接口扫码 --> <jpa:repositories base-package="com.zero.bos.dao"></jpa:repositories>
(3)dao包以及子包下的接口都可被扫码到。
下面是官方文档Demo。Interface
import org.springframework.data.repository.Repository; import com.zero.bos.domain.user.User; //接口定义使用说明 public interface UserDao extends Repository<User, String> { }
查看Repository的目录接口,如下图
它有增删改查和分页,我们最终是使用JpaRepository
这里可以看到接口的各种方法。但是好像看不到update方法,原因是save既可以save又可以update。
它是根据oid来进行识别的,如果oid是一个托管态的就save,如果oid是一个瞬时态的就update。
这里要确定接口包是可以被扫码的。
测试可以编写一个测试类。
package com.zero.bos.dao.user.test; 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.SpringJUnit4ClassRunner; import com.zero.bos.domain.user.User; import com.zero.bos.user.UserDao; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext-domain.xml") public class UserDaoTest { //注册接口实现类 @Autowired private UserDao userDao; @Test // 测试方法 不能有static 方法不能有参数 无返回值 否则无法进行测试 insert DML语句,需要加事务管理,所以建议不要在dao测而是在业务层测。 public void testAdd() { User u=new User(); u.setUsername("admin"); u.setPassword("123"); userDao.save(u); } }
但是编写测试类运行后会报错,因为是设计到增删改查就涉及到事务,所以需要配置事务。
上面这个错误是spring的包扫码路径问题,配置里写的是一个没有存在的包路径
<!-- 开始Spring注解@Controller @Service @Respository @Autowired @Scope --> <context:component-scan base-package="com.zero.bos"></context:component-scan>
官方建议要在业务层进行测试,而不是在dao层。
所以编写业务层(service)代码。
(1)业务层模块编写UserService和UserServiceImpl
UserService
package com.zero.bos.service.user; import java.util.List; import com.zero.bos.domain.user.User; public interface UserService { public void save(User user); public void delete(String id); public void delete(User user); public User findUserById(String id); public List<User> findAll(); public void updateUser(User user); }
UserServiceImpl
package com.zero.bos.service.user.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.zero.bos.domain.user.User; import com.zero.bos.service.user.UserService; import com.zero.bos.user.UserDao; @Service @Transactional public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; @Override public void save(User user) { userDao.save(user); } @Override public void delete(String id) { // id 是一个瞬时对象 userDao.delete(id); } @Override public void delete(User user) { userDao.delete(user); } @Override public User findUserById(String id) { return userDao.findOne(id); } @Override public List<User> findAll() { return userDao.findAll(); } @Override public void updateUser(User user) { //update 要是一个托管对象 userDao.save(user); } }
编写applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <!-- spring data jpa 事务管理 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
之后就可以进行业务层测试了。
测试代码
package com.zero.userService.test; 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.SpringJUnit4ClassRunner; import com.zero.bos.domain.user.User; import com.zero.bos.service.user.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:applicationContext-domain.xml","classpath:applicationContext-service.xml"}) public class UserServiceTest { @Autowired private UserService userService; @Test public void testAdd() { User u=new User(); u.setUsername("admin"); u.setPassword("123"); userService.save(u); } }
注意:一定要注意jps扫码包的路径和bean的id,能复制千万不要自己写,不要怕麻烦。
例如:报错信息是:java.lang.IllegalStateException: Failed to load ApplicationContext
<!-- Spring data jpa接口扫码 --> <jpa:repositories base-package="com.zero.bos.dao"></jpa:repositories>
类似的包扫码路径不对,扫描不到。
之后就可以正常的执行save操作了。
对象的ID和数据库表里的ID一致就叫做OID。
@Test public void testUpdate() { User user=new User(); user.setId("40288ce76281379e016281379f0f0000"); user.setUsername("霸天虎"); userService.updateUser(user); }
但是上面的代码会报错
not-null。测upadate的时候爆粗。
原因:这个修改是做的 全字段修改(update操作会把所有的字段都修改,上面的代码会将password置为null,因为没有赋值。但是数据库表的约束是password为非null)。
所以给password付一个值就可以了。
如果通过快照的方式 也不行。
User user = userService.findUserById("40288ce76281379e016281379f0f0000");
user.setUsername("刘德华");
因为entityManager默认是没有快照的。
如果是hibernate的话查询后修改就会同步到数据库中。
4、 门面类:
其实门面类就是将多个业务层分装到一个类中,之后通过门面类来统一管理。
@Test public void testAdd() { User u=new User(); u.setUsername("王五"); u.setPassword("123"); facadeService.getUserService().save(u); }
不要忘记@Service的注解。
通过门面类来调用不同的业务层对象实例。
5、JPQL查询说明(spring data jpa查询使用说明)
(1):根据方法名称 自动生成 jpql语句
如上图。
定义接口
//接口定义使用说明 //参数为查询的目标类型和主键类型,<User>通过User来操作对象。User类的id为String类型, public interface UserDao extends JpaRepository<User, String> { //用户名和密码查询用户 接口定义方法1:JPQL语句(HQL)2:根据接口方法名称 自动生成对应语句 3:命名查询 4:本地sql查询 5;参数占位符查询 //1、根据接口方法名称 自动生成SQL语句 public User findByUsernameAndPassword(String username,String password); }
userDao业务方法 必须符合命名规范 不用编写JPQL语句
业务层调用即可。
UserService
//登录 public User login(String name,String password);
UserServiceImpl
@Override public User login(String name, String password) { return userDao.findByUsernameAndPassword(name, password); }
UserServiceTest
@Test public void testLogin() { System.out.println(userService.login("zhangsan","123")); }
(2)命名查询 将jpql通一放在实体类上
实体类上面通一管理JPQL语句,JPQL就是一种面向对象关系的语句,类似HQL
测试代码中调用login方法会去找实体类的User.login。将参数带入。
//实体类通一管理jpql语句
@NamedQuery(name="User.login",query="from User where username=? and password=?")
命名查询的特点就是 方法名可以自定义
要求使用@NamedQuery 注解 在目标查询实体类上声明 接口UserDao声明方法 名称login
@Entity @Table(name="t_user",catalog="zero_bos") //实体类统一管理jpql语句 @NamedQuery(name="User.login",query="from User where username=? and password=?") public class User implements java.io.Serializable {
测试类中
@Test public void testLogin() { System.out.println(userService.login("zhangsan","123")); }
第三种方式:注解查询。
第一种和第二种都有自己的缺点:第一种比较复杂;第二种需要把JPQL语句写在实体类上
第三种是把JQPL写在UserDao接口方法上面。
例子:
UserDao
@Query("from User where username=?1 and password=?2") public User login1(String name,String password);
UserServiceImpl
@Override public User login(String name, String password) { // return userDao.findByUsernameAndPassword(name, password); return userDao.login1(name, password); }
测试结果,通过。
方法和语句都写在接口方法里面。
如果想写SQL语句,也可以。通过本地SQL查询
第四种:SQL查询
//第四种方法 SQL数据库语言 @Query("select * from t_user where username=?1 and password=?2") public User login2(String name,String password);
上面的方式是不行的,因为程序是不知道你使用的是SQL而不是JPQL。因此需要告知程序使用的 是SQL还是JPQL
可以看到Query里面有几种方式:nativeQuery 是是否开启MYsql语句的方式
//第四种方法 SQL数据库语言 @Query(nativeQuery=true,value="select * from t_user where username=?1 and password=?2") public User login2(String name,String password);
代码如上面所示。
这样就可以了。
第五种方式:占位符查询 通过名称 对应指定参数
@Query("from User where username=:username and password=:password") public User login3(@Param("username")String name,@Param("password")String password);
这种方式对使用SQL方式也适用,如下所示
//第四种方法 SQL数据库语言 @Query(nativeQuery=true,value="select * from t_user where username=:username and password=:password") public User login2(@Param("username")String name,@Param("password")String password);
6、登录业务的实现
首先将不同的模块的配置文件添加到web.xml中。
<!-- spring配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml, classpath:applicationContext.xml, classpath:applicationContext-domain.xml</param-value> </context-param>
鼠标放到登录上面会显示一个手的图标,说明这是一个超链接
<a href="${pageContext.request.contextPath}/page_common_index.action" id="loginform:j_id19" name="loginform:j_id19"> <span id="loginform:loginBtn" class="btn btn-login" style="margin-top:-36px;">登录</span> </a>
现在将超链接改为一个点击事件
<a href="javascript:void(0)" id="loginform:j_id19" name="loginform:j_id19" onclick="go()"> <span id="loginform:loginBtn" class="btn btn-login" style="margin-top: -36px;">登录</span> </a>
添加go事件;
// <!-- 声明式事务 提交表单 --> function go() { $("#loginform").submit(); }
<form id="loginform" name="loginform" method="post" class="niceform" action="${pageContext.request.contextPath}/user/userAction_login">
提交表单到 ${pageContext.request.contextPath}/user/userAction_login">
在Struts.xml中
客户端验证码
编写BaseAction
package com.zero.bos.web.action.base; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import org.springframework.beans.factory.annotation.Autowired; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.util.ValueStack; import com.zero.bos.service.facade.FacadeService; @SuppressWarnings("all") public class BaseAction<T> extends ActionSupport implements ModelDriven<T> { protected T model; // new T(); public T getModel() { // TODO Auto-generated method stub return model; } // 父类中 注入 门面业务层 @Autowired protected FacadeService serviceFacade; // 目的 获取子类参数化类型 // 父类构造方法中 使用 参数化泛型+反射 获取子类具体泛型对应类型 newInstance 创建实例 public BaseAction() { // 对model进行实例化, 通过子类 类声明的泛型 Type superclass = this.getClass().getGenericSuperclass(); // 转化为参数化类型 ParameterizedType parameterizedType = (ParameterizedType) superclass; // 获取一个泛型参数 Class<T> modelClass = (Class<T>) parameterizedType.getActualTypeArguments()[0]; try { model = modelClass.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // 父类封装通用方法 比如值栈操作 分页操作 session 操作 request操作 // 1: 值栈操作 获取 值栈 public ValueStack getValueStack() { return ActionContext.getContext().getValueStack(); } // 压入栈顶 public void push(Object obj) { getValueStack().push(obj); } // 压入栈顶map结构<> public void set(String key, Object obj) { getValueStack().set(key, obj); } // 2: session 操作 public HttpSession getSession() { return ServletActionContext.getRequest().getSession(); } public void setSessionAttribute(String key, Object obj) { getSession().setAttribute(key, obj); } public void removeSessionAttribute(String key) { getSession().removeAttribute(key); } public Object getSessionAttribute(String key) { return getSession().getAttribute(key); } // 3: request public HttpServletRequest getRequest() { return ServletActionContext.getRequest(); } public String getParameter(String key) { return getRequest().getParameter(key); } // 分页操作 接受页面 和 每页显示记录 protected int pageNum;// 页码 protected int pageSize;// 每页显示记录数 //struts2属性注入 将请求数据 自动注入 public void setPageNum(int pageNum) { this.pageNum = pageNum; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } }
UserAction
package com.zero.bos.web.action.user; import org.apache.commons.lang3.StringUtils; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.zero.bos.domain.user.User; import com.zero.bos.service.facade.FacadeService; import com.zero.bos.web.action.base.BaseAction; @Controller("userAction") @Scope("prototype") @Namespace("/user") // 根据页码的/user而来,不能乱写 @ParentPackage("bos") // 要进行扩展struts.xml中的 public class UserAction extends BaseAction<User> { //login_error错误了就重新登录,转发到login页面 @Action(value = "userAction_login", results = { @Result(name="login_error",location="/login.jsp"), @Result(name="login_ok",type="redirect",location="/index.jsp") }) // 页码的user/userAction_login public String login() { // 验证码校验 一次性验证码 用户名和密码校验 //1、验证码的校验 ,这里User是不包含的 验证码检验的 checkcode,但是我们封装在了BaseAction,这里就可以直接调用了 String input_checkcode=getParameter("checkcode"); // session.setAttribute("key", capstr); 从validatecode.jsp中拿到验证码 String session_code=(String)getSessionAttribute("key"); //进行比对,用户输入的和拿到的比对。这里可以跳过表单校验,不走post而走get就跳过了表单校验(1)用户没输 //不管正确与否都移除验证码,但是session_code变量里面已经有了。 removeSessionAttribute("key"); if(StringUtils.isNotBlank(input_checkcode)) { //客户提交的验证码不为null if(input_checkcode.equalsIgnoreCase(session_code)) { //验证码一样,需要门面类去调dao User existUser=serviceFacade.getUserService().login(model.getUsername(), model.getPassword()); if(existUser==null) { //数据库没查到 this.addActionError(this.getText("login.usernameOrPassword.error")); return "login_error"; }else { //将用户信息保存到session中 setSessionAttribute("exitUser", existUser); return "login_ok"; } }else { //错误信息,2:判断用户名和密码是否一致 一次性验证码,不管用户输入是否正确都要移除验证码。不太可能是空值。因为页面加载就会有session_code。 this.addActionError(this.getText("login.checkcode.error")); return "login_error"; } }else { //用户提交的验证码为null,然客户重新登录.国际化信息 this.addActionError(this.getText("login.nocheckcode.error")); return "login_error"; } // return ""; } }
this.addActionError(this.getText("login.nocheckcode.error"));
国际化信息
login.usernameOrPassword.error=\u7528\u6237\u540D\u6216\u8005\u5BC6\u7801\u9519\u8BEF login.checkcode.error=\u9A8C\u8BC1\u7801\u9519\u8BEF login.nocheckcode.error=\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801
如果登录成功返回“login_ok”
@Action(value = "userAction_login", results = { @Result(name="login_error",location="/login.jsp"), @Result(name="login_ok",type="redirect",location="/index.jsp")
直接跳转到index.jsp
如果登录错误就到login.jsp页面。
在validatecode.jsp
session.setAttribute("key", capstr);
将验证码放入到session中。
在login.jsp中添加
在顶部添加
<%@taglib prefix="s" uri="/struts-tags" %>
<font color="red"><s:actionerror/></font>
这里就会有错误信息
后端代码就先从login.jsp拿到输入的验证码以及session中的实际的验证码进行对比。
如果一直再进行输入的账户和密码是否在数据库中存在。
进行多个判断:验证码是否正确;验证码是否为null,账户密码是否为正确的。