1.新建项目,添加jar包
tomcat
jsp
struts、hibernate、spring
2.配置
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--配置spring监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--配置struts核心过滤器--> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
struts.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 禁用动态方法访问!userAction --> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <!-- 配置成开发模式 --> <constant name="struts.devMode" value="true" /> <!-- 配置拓展名为action --> <constant name="struts.action.extention" value="action" /> <!-- 把主题配置成simple --> <constant name="struts.ui.theme" value="simple" /> </struts>
3.测试spring
创建测试类TestService,并使用注解方式加入容器;
创建测试配置文件test-spring.xml(开启注解扫描)
<context:component-scan base-package="com.juaner.test.service.impl"></context:component-scan>
在主配置文件中引入配置文件
<import resource="classpath:com/juaner/*/conf/*-spring.xml"/>
测试spring
@Test public void testSpring(){ TestService ts= (TestService) ct.getBean("testService"); ts.say(); }
4.测试struts-spring
创建action,注入testService,并调用方法;
配置test-struts.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="test-action" namespace="/" extends="struts-default"> <action name="test_*" class="com.juaner.test.action.TestAction" method="{1}"> <result name="success">/WEB-INF/jsp/test/test.jsp</result> </action> </package> </struts>
在struts.xml中引入配置文件
<include file="com/juaner/test/conf/test-struts.xml"/>
访问action
5.测试hibernate-spring
配置数据源
<!-- 导入外部的properties配置文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 配置c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="jdbcUrl" value="${jdbcUrl}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="user" value="${user}"></property> <property name="password" value="${password}"></property> <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize" value="${initialPoolSize}"></property> <!--连接池中保留的最小连接数。Default: 3 --> <property name="minPoolSize" value="3"></property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize" value="${maxPoolSize}"></property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement" value="3"></property> <!--最大空闲时间,1800秒内未使用则连接被丢弃,若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime" value="1800"></property> </bean>
配置db.properties
jdbcUrl=jdbc:mysql://localhost:3306/itcastTax?useUnicode=true&characterEncoding=utf8 driverClass=com.mysql.jdbc.Driver user=root password=juaner767 initialPoolSize=10 maxPoolSize=30
新建实例类Person及相应的配置文件person.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.juaner.test.entity.Person" table="person"> <id name="id" type="java.lang.String"> <column name="id" length="32" /> <generator class="uuid" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="20" not-null="true" /> </property> </class> </hibernate-mapping>
配置hibernate sessionfactory属性及映射文件
<bean id="sf" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="javax.persistence.validation.mode">none</prop> </props> </property> <property name="mappingLocations"> <list> <value>classpath:com/juaner/test/entity/*.hbm.xml</value> </list> </property> </bean>
测试hibernate
ClassPathXmlApplicationContext ct = new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void testHibernate(){ SessionFactory sf = (SessionFactory) ct.getBean("sf"); Session session = sf.openSession(); Transaction transaction = session.beginTransaction(); session.save(new Person("人员1")); transaction.commit(); session.close(); }
6.事务控制
配置事务
<!--事务管理--> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sf"/> </bean> <!--事务增强--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="find*" read-only="true"/> <tx:method name="get*" read-only="true"/> <tx:method name="list*" read-only="true"/> <tx:method name="search*" read-only="true"/> <tx:method name="*" rollback-for="Throwable" /> </tx:attributes> </tx:advice> <!--aop--> <aop:config> <aop:pointcut id="serviceOperation" expression="bean(*Service)"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/> </aop:config> <bean id="testDao" class="com.juaner.test.dao.impl.TestDaoImpl"> <property name="sessionFactory" ref="sf"/> </bean>
开发TestDao、TestService接口及其实现类
public class TestDaoImpl extends HibernateDaoSupport implements TestDao{ @Override public void save(Person person) { getHibernateTemplate().save(person); } @Override public Person findPerson(Serializable id) { return getHibernateTemplate().get(Person.class,id); } }
<bean id="testDao" class="com.juaner.test.dao.impl.TestDaoImpl"> <property name="sessionFactory" ref="sf"/> </bean>
@Service("testService") public class TestServiceImpl implements TestService{ @Resource private TestDao testDao; @Override public void say() { System.out.println("hi"); } @Override public void save(Person person) { testDao.save(person); } @Override public Person findPerson(Serializable id) { return testDao.findPerson(id); } }
测试:必须用TestService接口接收,不能用TestServiceImpl接收,因为TestServiceImpl实现了TestService接口,生成的代理类也是TestService的子类,无法转成TestServiceImpl
@Test public void testReadOnly(){ TestService testService= (TestService) ct.getBean("testService"); System.out.println(testService.findPerson("fd5872945599fd07015599fd08580000").getName()); } @Test public void testRollBack(){ TestService testService= (TestService) ct.getBean("testService"); testService.save(new Person("人员4")); }
7.资源分类
8.配置log4j
导入jar包
配置log4j.xml
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p [%t] %c{1}:%L - %m%n
log4j.rootLogger=error, stdout,R
#log4j.logger.com.juaner=error
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=/itcastTax.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d [%t] %5p %c - %m%n
9.用户的增删改查
抽取BaseDao
BaseDao、BaseDaoImpl
public interface BaseDao<T> { public void save(T entity); public void delete(Serializable id); public void update(T entity); public T findObjectById(Serializable id); public List<T> findObjects(); }
反射
public abstract class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T>{ private Class<T> clazz; public BaseDaoImpl(){ //获取被实例化的类泛型 BaseDaoImpl<User>= ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); clazz = (Class<T>) pt.getActualTypeArguments()[0]; } @Override public void save(Object entity) { getHibernateTemplate().save(entity); } @Override public void delete(Serializable id) { getHibernateTemplate().delete(findObjectById(id)); } @Override public void update(Object entity) { getHibernateTemplate().update(entity); } @Override public T findObjectById(Serializable id) { return getHibernateTemplate().get(clazz,id); } @Override public List<T> findObjects() { Session session = getSession(); Query query = session.createQuery("from "+clazz.getSimpleName()); return query.list(); } }
User实体类及映射
public class User {
private String id;
private String dept;
private String name;
private String account;
private String password;
//头像
private String headImg;
private boolean gender;
private String state;
private String mobile;
private String email;
private Date birthday;
private String memo;
set...
get...
}
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.juaner.nsfw.user.entity.User" table="user"> <id name="id" type="java.lang.String"> <column name="id" length="32" /> <generator class="uuid" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="20" not-null="true" /> </property> <property name="dept" type="java.lang.String"> <column name="dept" length="20" not-null="true" /> </property> <property name="account" type="java.lang.String"> <column name="account" length="50" not-null="true" /> </property> <property name="password" type="java.lang.String"> <column name="password" length="50" not-null="true" /> </property> <property name="headImg" type="java.lang.String"> <column name="headImg" length="100" /> </property> <property name="gender" type="java.lang.Boolean"> <column name="gender" /> </property> <property name="email" type="java.lang.String"> <column name="email" length="50" /> </property> <property name="mobile" type="java.lang.String"> <column name="mobile" length="20" /> </property> <property name="birthday" type="java.util.Date"> <column name="birthday" length="10" /> </property> <property name="state" type="java.lang.String"> <column name="state" length="1" /> </property> <property name="memo" type="java.lang.String"> <column name="memo" length="200" /> </property> </class> </hibernate-mapping>
UserDao、UserDaoImpl
public interface UserDao extends BaseDao<User> { }
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao{ }
UserService、UserServiceImpl
public interface UserService { public void save(User user); public void delete(Serializable id); public void update(User user); public User findObjectById(Serializable id); public List<User> findObjects(); }
@Service("userService") public class UserServiceImpl implements UserService{ @Resource private UserDao userDao; @Override public void save(User user) { userDao.save(user); } @Override public void delete(Serializable id) { userDao.delete(id); } @Override public void update(User user) { userDao.update(user); } @Override public User findObjectById(Serializable id) { return userDao.findObjectById(id); } @Override public List<User> findObjects() { return userDao.findObjects(); } }
user-spring配置
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="userDao" class="com.juaner.nsfw.user.dao.impl.UserDaoImpl" parent="baseDao"> </bean> <context:component-scan base-package="com.juaner.nsfw.user.conf"/> </beans>
其中,baseDao在spring的主配置文件中配置,这样可以避免为sf的更改带来dao的大量改变。
<bean id="baseDao" abstract="true"> <property name="sessionFactory" ref="sf"/> </bean>
UserAction及struts配置
注意:add方法之后跳转需要重定向地址,但是listUI位于WEB-INF下,而且需要重新查询所有的user,所以需要redirectAction,调用listUI方法。
public class UserAction extends ActionSupport{ //IOC容器根据名称查询是否存在叫userService的bean,然后赋值 //所以必须叫userService,否则出错 @Resource private UserService userService; private List<User> userList; private User user; /** * 新增:跳转 */ public String addUI(){ return "addUI"; } /** *新增:增加 */ public String add(){ if(user != null) userService.save(user); return SUCCESS; } /** *删除:删除一个 */ public String delete(){ if(user != null && user.getId()!= null) userService.delete(user.getId()); return SUCCESS; } /** *删除:批量删除 */ public String deleteSelected(){ return SUCCESS; } /** *修改:跳转 */ public String editUI(){ return "editUI"; } /** *修改:修改 */ public String edit(){ if(user != null && user.getId()!= null) userService.update(user); return SUCCESS; } /** *查询 */ public String listUI(){ userList = userService.findObjects(); return "listUI"; } get... set... }
user-struts.xml
<struts> <package name="user-action" extends="struts-default" namespace="/nsfw"> <global-results> <result name="success">/WEB-INF/jsp/nsfw/user/listUI.jsp</result> </global-results> <action name="user_*" class="com.juaner.nsfw.user.action.UserAction" method="{1}"> <result name="{1}">/WEB-INF/jsp/nsfw/user/{1}.jsp</result> </action> </package> </struts>
struts iterator标签
<s:iterator value="userList" status="st"> <tr <s:if test="#st.odd"> bgcolor="f8f8f8"</s:if>> <td align="center"><input type="checkbox" name="selectedRow" value="<s:property value="id" />"/></td> <td align="center"><s:property value="name" /></td> <td align="center"><s:property value="account" /></td> <td align="center"><s:property value="dept" /></td> <td align="center"><s:property value="gender?'男':'女'"/> </td> <td align="center"><s:property value="email" /></td> <td align="center"> <a href="javascript:doEdit('<s:property value='id'/>')">编辑</a> <a href="javascript:doDelete('<s:property value='id'/>')">删除</a> </td> </tr> </s:iterator>
10.使用datepicker插件
在js中导入WdataPicker,并引入
<script type="text/javascript" src="${basePath}js/datepicker/WdatePicker.js"></script>
使用
<s:textfield id="birthday" name="user.birthday" readonly="true" onfocus="WdatePicker({skin:'whyGreen',dateFmt:'yyyy-MM-dd'})"/>
<s:textfield id="birthday" name="user.birthday" readonly="true" onfocus="WdatePicker({skin:'whyGreen',dateFmt:'yyyy-MM-dd'})"> <s:param name="value"><s:date name='user.birthday' format='yyyy-MM-dd' /></s:param> </s:textfield>
11.头像的上传与下载
struts上传文件,需要一个File,contentType,filename。
add.jsp
提交的表单enctype
<form id="form" name="form" action="${basePath}nsfw/user_add.action" method="post" enctype="multipart/form-data">
<tr> <td class="tdBg" width="200px">头像:</td> <td> <input type="file" name="headImg"/> </td> </tr>
UserAction方法添加字段及上传方法
private File headImg; private String headImgContentType; private String headImgFileName;
public String add(){ try { if(user != null) { if (headImg != null) { //获取保存路径的绝对地址 String filePath= ServletActionContext.getServletContext().getRealPath("upload/user"); //防止被覆盖需要重命名,中文文件名可能无法正常显示 String fileName = UUID.randomUUID().toString().replace("-","")+headImgFileName.substring(headImgFileName.lastIndexOf(".")); //复制文件 FileUtils.copyFile(headImg,new File(filePath,fileName)); //设置用户头像路径 user.setHeadImg("user/"+fileName); } userService.save(user); } } catch (IOException e) { e.printStackTrace(); } return "list"; }
edit.jsp
<td> <s:if test="%{user.headImg != null && user.headImg != ''}"> <img src="${basePath}upload/<s:property value='user.headImg'/> " width="100" height="100"/> <%--防止图片丢失--%> <s:hidden name="user.headImg"/> </s:if> <input type="file" name="headImg"/> </td>
12.POI实现excel导入导出
导入和导出按钮设置
function doImportExcel(){ document.forms[0].action = "${basePath}nsfw/user_importExcel.action"; document.forms[0].submit(); } function doExportExcel(){ window.open("${basePath}nsfw/user_exportExcel2.action"); }
UserAction中添加方法
//导出数据 public void exportExcel(){ try { users = userService.findObjects(); HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType("application/x-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + new String("用户列表.xls".getBytes(), "ISO-8859-1")); ServletOutputStream outputStream = response.getOutputStream(); userService.exportExcel(outputStream,users); if(outputStream != null) outputStream.close(); } catch (Exception e) { e.printStackTrace(); } } //导入数据 private File userExcel; private String userExcelContentType; private String userExcelFileName; public String importExcel(){ if(userExcel != null) { if(userExcelFileName.matches("^.+\.(?i)((xls)|(xlsx))$")){ try { userService.importExcel(userExcel,userExcelFileName); } catch (IOException e) { e.printStackTrace(); } } } return "list"; } public File getUserExcel() { return userExcel; } public void setUserExcel(File userExcel) { this.userExcel = userExcel; } public String getUserExcelContentType() { return userExcelContentType; } public void setUserExcelContentType(String userExcelContentType) { this.userExcelContentType = userExcelContentType; } public String getUserExcelFileName() { return userExcelFileName; } public void setUserExcelFileName(String userExcelFileName) { this.userExcelFileName = userExcelFileName; }
抽取方法到ExcelUtil
public class ExcelUtil { public static void exportUserExcel(List<User> userList, ServletOutputStream outputStream) throws Exception{ HSSFWorkbook workbook = new HSSFWorkbook(); CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, 4); HSSFCellStyle headStyle = createCellStyle(workbook, (short) 16); HSSFCellStyle colStyle = createCellStyle(workbook, (short) 13); HSSFSheet sheet = workbook.createSheet("用户列表"); sheet.addMergedRegion(cellRangeAddress); HSSFRow headRow = sheet.createRow(0); HSSFCell headCell = headRow.createCell(0); headCell.setCellStyle(headStyle); headCell.setCellValue("用户列表"); sheet.setDefaultColumnWidth(25); HSSFRow colRow = sheet.createRow(1); String[] titles = new String[]{"用户名","账户名","所属部门","性别","电子邮箱"}; for(int i=0;i<titles.length;i++){ HSSFCell cell = colRow.createCell(i); cell.setCellStyle(colStyle); cell.setCellValue(titles[i]); } if(userList!=null&& userList.size()>0) { for(int i=0;i<userList.size();i++) { HSSFRow row = sheet.createRow(i + 2); HSSFCell cell1 = row.createCell(0); cell1.setCellValue(userList.get(i).getName()); HSSFCell cell2 = row.createCell(1); cell2.setCellValue(userList.get(i).getAccount()); HSSFCell cell3 = row.createCell(2); cell3.setCellValue(userList.get(i).getDept()); HSSFCell cell4 = row.createCell(3); cell4.setCellValue(userList.get(i).isGender()?"男":"女"); HSSFCell cell5 = row.createCell(4); cell5.setCellValue(userList.get(i).getEmail()); } } workbook.write(outputStream); workbook.close(); } private static HSSFCellStyle createCellStyle(HSSFWorkbook workbook, short fontSize) { HSSFCellStyle style = workbook.createCellStyle(); style.setAlignment(HSSFCellStyle.ALIGN_CENTER); style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); HSSFFont headFont = workbook.createFont(); headFont.setBold(true); headFont.setFontHeightInPoints(fontSize); style.setFont(headFont); return style; } }
给UserService和UserServiceImpl添加方法
@Override public void exportExcel(ServletOutputStream outputStream, List<User> users) throws IOException { ExcelUtil.exportUserExcel(outputStream,users); } @Override public void importExcel(File userExcel, String fileName) throws IOException { FileInputStream fileInputStream = new FileInputStream(userExcel); //判断03或者07 boolean is03Excel = fileName.matches("^.+\.(?i)(xls)&"); Workbook workbook = is03Excel?new HSSFWorkbook(fileInputStream):new XSSFWorkbook(fileInputStream); Sheet sheet = workbook.getSheetAt(0); if(sheet.getPhysicalNumberOfRows() > 2){ User user = null; for(int i=2;i<sheet.getPhysicalNumberOfRows();i++){ Row row = sheet.getRow(i); String acount = row.getCell(1).getStringCellValue(); if(isUserExists(acount)) continue; user = new User(); user.setName(row.getCell(0).getStringCellValue()); user.setAccount(row.getCell(1).getStringCellValue()); user.setDept(row.getCell(2).getStringCellValue()); user.setGender(row.getCell(3).getStringCellValue().equals("男")?true:false); // 如果电话用科学计数法,转为string String mobile = ""; try { mobile = row.getCell(4).getStringCellValue(); }catch (Exception e){ double dMobile = row.getCell(4).getNumericCellValue(); mobile = BigDecimal.valueOf(dMobile).toString(); } user.setMobile(mobile); user.setEmail(row.getCell(5).getStringCellValue()); user.setBirthday(row.getCell(6).getDateCellValue()); user.setState(User.USER_STATE_VALID); user.setPassword("123456"); save(user); } } workbook.close(); fileInputStream.close(); }
导入数据
action中
public String importExcel(){ if(userExcel !=null){ try { if(userExcelFileName.matches("^.+\.(?i)((xls)|(xlsx))$")){ userService.importExcel(userExcel,userExcelFileName); } }catch (Exception e){ e.printStackTrace(); } } return SUCCESS; }
service中
public void importExcel(File userExcel, String userExcelFileName) throws Exception { boolean is03Excel = userExcelFileName.matches("^.+\.(?i)(xls)$"); FileInputStream inputStream = new FileInputStream(userExcel); Workbook workbook = is03Excel ? new HSSFWorkbook(inputStream) : new XSSFWorkbook(inputStream); Sheet sheet = workbook.getSheetAt(0); if(sheet.getPhysicalNumberOfRows()>2){ for(int i=2;i<sheet.getPhysicalNumberOfRows();i++){ User user = new User(); Row row = sheet.getRow(i); String name = row.getCell(0).getStringCellValue(); user.setName(name); String account = row.getCell(1).getStringCellValue(); user.setAccount(account); String dept = row.getCell(2).getStringCellValue(); user.setDept(dept); String gender = row.getCell(3).getStringCellValue(); user.setGender(true); String mobile = ""; try { mobile = row.getCell(4).getStringCellValue(); }catch (Exception e){ double dmobile = row.getCell(4).getNumericCellValue(); mobile = BigDecimal.valueOf(dmobile).toString(); } user.setMobile(mobile); String email = row.getCell(5).getStringCellValue(); user.setEmail(email); Date birthday = row.getCell(6).getDateCellValue(); user.setBirthday(birthday); user.setPassword("123456"); user.setState(User.USER_STATE_VALID); save(user); } } inputStream.close(); }
13账号唯一性校验
在增加和修改页面中需要进行账号唯一性校验。编辑页面查找账号唯一性需要先排除正在编辑的用户的账号。
spring提供了StringUtils.isNotBlank来检查字符串。
点击提交按钮后,需要使用ajax同步来验证是否账号唯一。
addUI.jsp
<script type="text/javascript"> var result = false; function verifyAccount(){ var account = $("#account").val(); if(account.trim()=="") return ; var url = "${basePath}nsfw/user_verifyAccount.action?time="+new Date().getTime(); var content = { "user.account":account }; $.ajax({ type:"POST", url:url, data:content, async:false, success:function(msg) { if ("true" == msg){ alert("账号已经存在,请使用其他账号!"); $("#account").focus(); result = false; }else{ result = true; } } }) } function doSubmit(){ verifyAccount(); if(result==true) document.forms[0].submit(); } </script>
editUI.jsp
<script type="text/javascript"> var result = false; function verifyAccount(){ var account = $("#account").val(); if(account.trim()=="") return ; var url = "${basePath}nsfw/user_verifyAccount.action?time="+new Date().getTime(); var content = { "user.account":account, "user.id":"${user.id}" }; $.ajax({ type:"POST", url:url, data:content, async:false, success:function(msg) { if ("true" == msg){ alert("账号已经存在,请使用其他账号!"); $("#account").focus(); result = false; }else{ result = true; } } }) } function doSubmit(){ verifyAccount(); if(result==true) document.forms[0].submit(); } </script>
aciton
public void verifyAccount() throws IOException { HttpServletResponse response = ServletActionContext.getResponse(); PrintWriter writer = response.getWriter(); String msg = "false"; if(user != null && StringUtils.isNotBlank(user.getAccount())){ int ret = userService.findUserByAccountAndId(user.getAccount(),user.getId()); if(ret >0){ msg = "true"; } } writer.write(msg); writer.flush(); writer.close(); }
dao
public int findUserByAccountAndId(String account,String id) { String hql = "from User where account ="+"'"+account+"'"; if(StringUtils.isNotBlank(id)) hql+=" and id != "+"'"+id+"'"; List list = getSession().createQuery(hql).list(); return list.size(); }
14.异常和返回结果类型
15.角色与权限
角色与权限是多对多的关系。但是由于权限没有对应的实体和表,是固定的5个值,所以角色和角色权限(中间表)是一对多的关系。RolePrivilege只有一个属性RolePrivilegeId,RolePrivilegeId作为联合主键类,必须要实现Serializable接口并且重写hashcode和equals方法。
Role
public class Role { private String roleId; private String name; private String state; private Set<RolePrivilege> rolePrivileges; public static String ROLE_STATE_VALID = "1"; public static String ROLE_STATE_INVALID = "0"; get... set... }
Role.hbm.xml
<hibernate-mapping> <class name="com.juaner.nsfw.role.entity.Role" table="t_role"> <id name="roleId" type="java.lang.String"> <column name="r_id" length="32"/> <generator class="uuid"/> </id> <property name="name" type="java.lang.String"> <column name="r_name" length="20" not-null="true"/> </property> <property name="state" type="java.lang.String"> <column name="r_state" length="1"/> </property> <set name="rolePrivileges" inverse="true" lazy="false" cascade="save-update,delete"> <key> <column name="r_id" /> </key> <one-to-many class="com.juaner.nsfw.role.entity.RolePrivilege"/> </set> </class> </hibernate-mapping>
RolePrivilege
public class RolePrivilege implements Serializable{ private RolePrivilegeId id; get... set... }
RolePrivilegeId
public class RolePrivilegeId implements Serializable{ private String code; private Role role; get... set... equals... hashcode... }
RolePrivilege.hbm.xml
<hibernate-mapping> <class name="com.juaner.nsfw.role.entity.RolePrivilege" table="t_roleprivilege"> <composite-id name="id" class="com.juaner.nsfw.role.entity.RolePrivilegeId"> <key-many-to-one name="role" lazy="false" class="com.juaner.nsfw.role.entity.Role"> <column name="r_id"/> </key-many-to-one> <key-property name="code" type="java.lang.String"> <column name="p_code" length="20"/> </key-property> </composite-id> </class> </hibernate-mapping>
跳转到添加页面和修改页面都要在域中设置权限map
public String addUI(){ ActionContext.getContext().getContextMap().put("privilegeMap", Constant.PRIVILEGE_MAP); return "addUI"; }
添加角色
public String add()throws Exception{ if(role != null){ if(privilegeIds!=null){ Set<RolePrivilege> set = new HashSet<>(); for(String code:privilegeIds){ set.add(new RolePrivilege(new RolePrivilegeId(code,role))); } role.setRolePrivileges(set); } roleService.save(role); } return SUCCESS; }
跳转到修改页面
public String editUI(){ if(role != null && role.getRoleId()!= null) { role = roleService.findObjectById(role.getRoleId()); ActionContext.getContext().getContextMap().put("privilegeMap", Constant.PRIVILEGE_MAP); if(role.getRolePrivileges().size()>0){ privilegeIds = new String[role.getRolePrivileges().size()]; int i=0; for(RolePrivilege roleprivilege:role.getRolePrivileges()){ privilegeIds[i++] = roleprivilege.getId().getCode(); } } } return "editUI"; }
修改角色,在设置新的权限之前要删掉旧的权限
public String edit()throws Exception{ if(role != null && role.getRoleId()!= null){ if(privilegeIds!=null){ Set<RolePrivilege> set = new HashSet<>(); for(String code:privilegeIds){ set.add(new RolePrivilege(new RolePrivilegeId(code,role))); } role.setRolePrivileges(set); } roleService.update(role); } return SUCCESS; }
16.struts标签
遍历显示
<s:iterator value="roleList" status="st"> <tr <s:if test="#st.odd"> bgcolor="f8f8f8"</s:if>> <td align="center"><input type="checkbox" name="selectedRow" value="<s:property value='roleId' />"/></td> <td align="center"><s:property value="name" /> </td> <td align="center"> <s:iterator value="rolePrivileges"> <s:property value="#privilegeMap[id.code]"/> </s:iterator> </td> <td align="center"><s:property value="state='1'?'有效':'无效'" /></td> <td align="center"> <a href="javascript:doEdit('<s:property value='roleId' />')">编辑</a> <a href="javascript:doDelete('<s:property value='roleId' />')">删除</a> </td> </tr> </s:iterator>
checkboxlist
<s:checkboxlist list="#privilegeMap" name="privilegeIds"></s:checkboxlist>
17.用户角色
用户类和角色类及其映射都无法再修改,所以需要将用户类和中间表类独立出来。用户和角色是多对多的关系。所以只要创建作为中间表的UserRole,它具有联合主键性质。因为可能有根据用户查询角色的需求,没有根据角色查询用户的需求,所以联合主键类的设计如下:
添加
<s:checkboxlist list="#roleList" name="userRoleIds" listKey="roleId" listValue="name"></s:checkboxlist>
添加用户角色关系时,虽然联合主键类中的对象是Role,但表中实际保存的是roleId,所以不需要查询出响应的Role,只要保存有roleId属性的Role就可以了。虽然保存时user的id属性不存在,但是hibernate在save或update方法之后会对user的其他属性进行回填,所以在save后可以使用id属性。
service
public void saveUserAndRole(User user, String... userRoleIds) { save(user); System.out.println(user.getId()); for(String roleId:userRoleIds){ UserRole userRole = new UserRole(); Role role = new Role(roleId); userRole.setId(new UserRoleId(role,user.getId())); userDao.saveUserRole(userRole); } }
修改时,跳转到修改页面之前,需要在域对象中放置当前用户的角色
public String editUI(){ ActionContext.getContext().getContextMap().put("roleList",roleService.findObjects()); if(user != null && user.getId()!= null) { user = userService.findObjectById(user.getId()); List<UserRole> userRoles = userService.getUserRolesByUserId(user.getId()); if(userRoles!=null&&userRoles.size()>0){ userRoleIds = new String[userRoles.size()]; int i=0; for(UserRole userRole:userRoles){ userRoleIds[i++] = userRole.getId().getRole().getRoleId(); } } } return "editUI"; }
修改时,需要先删除旧的角色,再添加新的角色
public void updateUserAndRole(User user, String... userRoleIds) { update(user); userDao.deleteUserRoleByUserId(user.getId()); for(String roleId:userRoleIds){ UserRole userRole = new UserRole(); Role role = new Role(roleId); userRole.setId(new UserRoleId(role,user.getId())); userDao.saveUserRole(userRole); } }
18.异常
对特定异常类的结果映射,其他action的映射需要继承base-default。
对实现了StrutsResultSupport的类的结果映射(配置了对该类的结果映射名后,如果某个action方法返回该映射名,会由该类的doExecute()方法进行处理)。
public class SysResultAction extends StrutsResultSupport { @Override protected void doExecute(String s, ActionInvocation actionInvocation) throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); BaseAction action = (BaseAction) actionInvocation.getAction(); System.out.println("进入了SysResultAction......"); } }
<package name="base-default" extends="struts-default"> <result-types> <result-type name="errorAction" class="com.juaner.core.action.SysResultAction"></result-type> </result-types> <global-results> <result name="errorAction" type="errorAction">/WEB-INF/jsp/error.jsp</result> <result name="error">/WEB-INF/jsp/error.jsp</result> <result name="input">/WEB-INF/jsp/error.jsp</result> </global-results> <global-exception-mappings> <exception-mapping exception="com.juaner.core.exception.ActionException" result="error"></exception-mapping> <exception-mapping exception="java.lang.Exception" result="input"></exception-mapping> </global-exception-mappings> </package>