人事管理系统总结
作者:互联网
人事管理系统
文章目录
- 人事管理系统
1.创建项目
1.1 使用逆向工程创建项目
自动生成实体类bean,和mapper接口和映射文件
1.2 pom.xml的编写导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!-- 切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!-- springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<!-- fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<!-- jackson-databind-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<!-- servlet api可以使用原生的servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 分页-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!--shiro-spring-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- spring-aspects-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>jspapi</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
1.2配置文件的编写
1.2.1 applicationContext.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:mybatis="http://mybatis.org/schema/mybatis-spring"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.配置组件扫描,主要扫描service和mapper包-->
<context:component-scan base-package="com.hrf.service,com.hrf.mapper"/>
<!-- 2.引入外部的属性文件-->
<context:property-placeholder location="classpath*:jdbc.properties"/>
<!-- 3.配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 4.配置sqlsessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 4.1配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!-- 4.4加载设置-->
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true"/>
<property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"/>
</bean>
</property>
<!-- 4.5 插件 分页插件-->
<property name="plugins">
<list>
<bean class="com.github.pagehelper.PageInterceptor"/>
</list>
</property>
<!-- 4.2定义别名-->
<property name="typeAliasesPackage" value="com.hrf.bean"/>
<!-- 4.2加载mybatis核心配置文件configLocation-->
<!-- <property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<!-- 4.3加载mapper里面的配置文件-->
<property name="mapperLocations" value="classpath*:com/hrf/mapper/*.xml"/>
</bean>
<!-- 5.搜索mapper映射接口-->
<mybatis:scan base-package="com.hrf.mapper"/>
<!-- 6.事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 7.事务切面配置-->
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 8.事务切面与切入点的关联-->
<aop:config proxy-target-class="true">
<aop:pointcut id="p" expression="execution(* com.hrf.service.*.*(..))"/>
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="p"/>
</aop:config>
</beans>
1.2.2 Springmvc.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.组件扫描,主要是扫描controller-->
<context:component-scan base-package="com.hrf.controller"/>
<!-- 2.开启注解-->
<mvc:annotation-driven>
<!-- 如果fastjson返回json数据需要继续配置-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="utf-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 3.配置视图解析器-->
<!-- <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!-- <property name="prefix" value="/"/>-->
<!-- <property name="suffix" value=".jsp"/>-->
<!-- </bean>-->
<!-- <mvc:view-resolvers>-->
<!-- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!-- <property name="prefix" value="/"/>-->
<!-- <property name="suffix" value=".jsp"/>-->
<!-- </bean>-->
<!-- </mvc:view-resolvers>-->
<!-- 4.处理静态资源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- 指定使用Cglib作为AOP的动态代理实现 -->
<aop:config proxy-target-class="true"/>
<!-- 开启Shiro权限注解支持 -->
<!-- <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">-->
<!-- <property name="securityManager" ref="securityManager"/>-->
<!-- </bean>-->
<!-- 处理注解检查权限页面报错异常 -->
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
<!-- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">-->
<!-- <property name="exceptionMappings"> <props>-->
<!-- <prop key="org.apache.shiro.authz.UnauthorizedException">/forbidden.jsp</prop>-->
<!-- <prop key="org.apache.shiro.authz.AuthorizationException">/forbidden.jsp</prop>-->
<!-- </props>-->
<!-- </property>-->
<!-- </bean>-->
</beans>
1.2.3 jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/hrmanagement?serverTimeZone=UTC
jdbc.username=root
jdbc.password=0429
1.2.4 log4j.properties
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.com.hrf.mapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
1.3 与web集成(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_4_0.xsd"
version="4.0">
<!-- 设置欢迎页面-->
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/loginForm.jsp</welcome-file>
</welcome-file-list>
<!-- 配置过滤器-->
<filter>
<filter-name>code</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>code</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置中央处理器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 绑定springmvc-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring上下文的监听器 配置监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- shiro的过滤器-->
<!-- <filter>-->
<!-- <filter-name>shiroFilter</filter-name>-->
<!-- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>-->
<!-- </filter>-->
<!-- <filter-mapping>-->
<!-- <filter-name>shiroFilter</filter-name>-->
<!-- <url-pattern>/*</url-pattern>-->
<!-- <dispatcher>REQUEST</dispatcher>-->
<!-- <dispatcher>FORWARD</dispatcher>-->
<!-- </filter-mapping>-->
<!-- 设置会话配置session-timeout 5 分钟-->
<!-- <session-config>-->
<!-- <session-timeout>5</session-timeout>-->
<!-- </session-config>-->
</web-app>
注意: 设置默认的欢迎页面 loginForm.jsp进行登录,看上面的代码.
1.4导入工具类
1.4.1 分页标签
package com.hrf.util;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* 分页标签
*/
public class PagerTag extends SimpleTagSupport {
/** 定义请求URL中的占位符常量 */
private static final String TAG = "{0}";
/** 当前页码 */
private int pageIndex;
/** 每页显示的数量 */
private int pageSize;
/** 总记录条数 */
private int recordCount;
/** 请求URL page.action?pageIndex={0}*/
private String submitUrl;
/** 样式 */
private String style = "sabrosus";
/** 定义总页数 */
private int totalPage = 0;
/** 在页面上引用自定义标签就会触发一个标签处理类 */
@Override
public void doTag() throws JspException, IOException {
/** 定义它拼接是终的结果 */
StringBuilder res = new StringBuilder();
/** 定义它拼接中间的页码 */
StringBuilder str = new StringBuilder();
/** 判断总记录条数 */
if (recordCount > 0){ //1499 / 15 = 100
/** 需要显示分页标签,计算出总页数 需要分多少页 */
totalPage = (this.recordCount - 1) / this.pageSize + 1;
/** 判断上一页或下一页需不需要加a标签 */
if (this.pageIndex == 1){ // 首页
str.append("<span class='disabled'>上一页</span>");
/** 计算中间的页码 */
this.calcPage(str);
/** 下一页需不需要a标签 */
if (this.pageIndex == totalPage){
/** 只有一页 */
str.append("<span class='disabled'>下一页</span>");
}else{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex + 1));
str.append("<a href='"+ tempUrl +"'>下一页</a>");
}
}else if (this.pageIndex == totalPage){ // 尾页
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex - 1));
str.append("<a href='"+ tempUrl +"'>上一页</a>");
/** 计算中间的页码 */
this.calcPage(str);
str.append("<span class='disabled'>下一页</span>");
}else{ // 中间
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex - 1));
str.append("<a href='"+ tempUrl +"'>上一页</a>");
/** 计算中间的页码 */
this.calcPage(str);
tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex + 1));
str.append("<a href='"+ tempUrl +"'>下一页</a>");
}
/** 拼接其它的信息 */
res.append("<table width='100%' align='center' style='font-size:13px;' class='"+ style +"'>");
res.append("<tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>" + str.toString());
res.append(" 跳转到 <input style='text-align: center;BORDER-RIGHT: #aaaadd 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #aaaadd 1px solid; PADDING-LEFT: 5px; PADDING-BOTTOM: 2px; MARGIN: 2px; BORDER-LEFT: #aaaadd 1px solid; COLOR: #000099; PADDING-TOP: 2px; BORDER-BOTTOM: #aaaadd 1px solid; TEXT-DECORATION: none' type='text' size='2' id='pager_jump_page_size'/>");
res.append(" <input type='button' style='text-align: center;BORDER-RIGHT: #dedfde 1px solid; PADDING-RIGHT: 6px; BACKGROUND-POSITION: 50% bottom; BORDER-TOP: #dedfde 1px solid; PADDING-LEFT: 6px; PADDING-BOTTOM: 2px; BORDER-LEFT: #dedfde 1px solid; COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; BORDER-BOTTOM: #dedfde 1px solid; TEXT-DECORATION: none' value='确定' id='pager_jump_btn'/>");
res.append("</td></tr>");
res.append("<tr align='center'><td style='font-size:13px;'><tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>");
/** 开始条数 */
int startNum = (this.pageIndex - 1) * this.pageSize + 1;
/** 结束条数 */
int endNum = (this.pageIndex == this.totalPage) ? this.recordCount : this.pageIndex * this.pageSize;
res.append("总共<font color='red'>"+ this.recordCount +"</font>条记录,当前显示"+ startNum +"-"+ endNum +"条记录。");
res.append("</td></tr>");
res.append("</table>");
res.append("<script type='text/javascript'>");
res.append(" document.getElementById('pager_jump_btn').onclick = function(){");
res.append(" var page_size = document.getElementById('pager_jump_page_size').value;");
res.append(" if (!/^[1-9]\\d*$/.test(page_size) || page_size < 1 || page_size > "+ this.totalPage +"){");
res.append(" alert('请输入[1-"+ this.totalPage +"]之间的页码!');");
res.append(" }else{");
res.append(" var submit_url = '" + this.submitUrl + "';");
res.append(" window.location = submit_url.replace('"+ TAG +"', page_size);");
res.append(" }");
res.append("}");
res.append("</script>");
}else{
res.append("<table align='center' style='font-size:13px;'><tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>总共<font color='red'>0</font>条记录,当前显示0-0条记录。</td></tr></table>");
}
this.getJspContext().getOut().print(res.toString());
}
/** 计算中间页码的方法 */
private void calcPage(StringBuilder str) {
/** 判断总页数 */
if (this.totalPage <= 11){
/** 一次性显示全部的页码 */
for (int i = 1; i <= this.totalPage; i++){
if (this.pageIndex == i){
/** 当前页码 */
str.append("<span class='current'>"+ i +"</span>");
}else{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='"+ tempUrl +"'>"+ i +"</a>");
}
}
}else{
/** 靠近首页 */
if (this.pageIndex <= 8){
for (int i = 1; i <= 10; i++){
if (this.pageIndex == i){
/** 当前页码 */
str.append("<span class='current'>"+ i +"</span>");
}else{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='"+ tempUrl +"'>"+ i +"</a>");
}
}
str.append("...");
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(this.totalPage));
str.append("<a href='"+ tempUrl +"'>"+ this.totalPage +"</a>");
}
/** 靠近尾页 */
else if (this.pageIndex + 8 >= this.totalPage){
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(1));
str.append("<a href='"+ tempUrl +"'>1</a>");
str.append("...");
for (int i = this.totalPage - 10; i <= this.totalPage; i++){
if (this.pageIndex == i){
/** 当前页码 */
str.append("<span class='current'>"+ i +"</span>");
}else{
tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='"+ tempUrl +"'>"+ i +"</a>");
}
}
}
/** 在中间 */
else{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(1));
str.append("<a href='"+ tempUrl +"'>1</a>");
str.append("...");
for (int i = this.pageIndex - 4; i <= this.pageIndex + 4; i++){
if (this.pageIndex == i){
/** 当前页码 */
str.append("<span class='current'>"+ i +"</span>");
}else{
tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='"+ tempUrl +"'>"+ i +"</a>");
}
}
str.append("...");
tempUrl = this.submitUrl.replace(TAG, String.valueOf(this.totalPage));
str.append("<a href='"+ tempUrl +"'>"+ this.totalPage +"</a>");
}
}
}
/** setter 方法 */
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public void setRecordCount(int recordCount) {
this.recordCount = recordCount;
}
public void setSubmitUrl(String submitUrl) {
this.submitUrl = submitUrl;
}
public void setStyle(String style) {
this.style = style;
}
}
1.4.2验证码有关
package com.hrf.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;
import javax.imageio.ImageIO;
public class VerifyCodeUtils {
//使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符,以及占用太宽的字符W
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVXYZ";
private static Random random = new Random();
/**
* 使用系统默认字符源生成验证码
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize){
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources){
if(sources == null || sources.length() == 0){
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for(int i = 0; i < verifySize; i++){
verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
}
return verifyCode.toString();
}
/**
* 生成随机验证码文件,并返回验证码值
* @param w
* @param h
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, outputFile, verifyCode);
return verifyCode;
}
/**
* 输出随机验证码图片流,并返回验证码值
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, os, verifyCode);
return verifyCode;
}
/**
* 生成指定验证码图像文件
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
if(outputFile == null){
return;
}
File dir = outputFile.getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
try{
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
outputImage(w, h, fos, code);
fos.close();
} catch(IOException e){
throw e;
}
}
/**
* 输出指定验证码图片流
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for(int i = 0; i < colors.length; i++){
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
g2.setColor(Color.GRAY);// 设置边框色
g2.fillRect(0, 0, w, h);
Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, w, h-4);
//绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
}
// 添加噪点
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++) {
int x = random.nextInt(w);
int y = random.nextInt(h);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
shear(g2, w, h, c);// 使图片扭曲
g2.setColor(getRandColor(100, 160));
int fontSize = h-4;
Font font = new Font("Algerian", Font.PLAIN, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for(int i = 0; i < verifySize; i++){
//AffineTransform affine = new AffineTransform();
//affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
//g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
private static Color getRandColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static int getRandomIntColor() {
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb) {
color = color << 8;
color = color | c;
}
return color;
}
private static int[] getRandomRgb() {
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255);
}
return rgb;
}
private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private static void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private static void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
}
1.4.3分页PageModel
package com.hrf.util;
import java.io.Serializable;
public class PageModel implements Serializable{
private Integer pageIndex=1;
private Integer pageSize=6;
private Integer recordCount;
public Integer getPageIndex() {
return pageIndex;
}
public void setPageIndex(Integer pageIndex) {
this.pageIndex = pageIndex;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getRecordCount() {
return recordCount;
}
public void setRecordCount(Integer recordCount) {
this.recordCount = recordCount;
}
public PageModel() {
super();
}
public PageModel(Integer pageIndex, Integer pageSize, Integer recordCount) {
super();
this.pageIndex = pageIndex;
this.pageSize = pageSize;
this.recordCount = recordCount;
}
}
可以不使用分页,但是需要使用分页插件
2.编写项目代码
2.1 创建controller层
2.2 创建service层
3. 用户登录模块的实现
3.1UserLoginController的实现,使用了shiro
package com.hrf.controller;
import com.hrf.bean.User;
import com.hrf.service.UserLoginService;
import com.hrf.util.VerifyCodeUtils;
import com.sun.org.apache.regexp.internal.RE;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@Controller
@Slf4j
public class UserLoginController {
@Autowired
private UserLoginService userLoginService;
// 1.检查验证码
@RequestMapping("/checkCode")
public void checkCode(String num, HttpSession session, HttpServletResponse response) throws IOException {
ServletOutputStream outputStream = response.getOutputStream();
int w = 200, h = 80;
String code = VerifyCodeUtils.generateVerifyCode(4);
session.setAttribute("code",code);
VerifyCodeUtils.outputImage(w, h, outputStream, code);
outputStream.close();
}
// 2.登录
@RequestMapping("/login")
public String login(String loginname,String password, String user_input_verifyCode,Model model,HttpSession session) throws Exception {
// 如果用户名和密码都不为空,调用shiro验证用户名,密码是否正确
if (loginname==null||("").equals(loginname)){
model.addAttribute("msg","登录名不能为空");
throw new Exception("用户名不能为空");
}
if (password==null||("").equals(password)){
model.addAttribute("msg","密码不能为空");
throw new Exception("密码不能为空");
}
// if (user_input_verifyCode==null||("").equals(user_input_verifyCode)){
// model.addAttribute("msg","验证码不能为空");
// throw new Exception("验证码不能为空");
// }
// 将username和password封装为token对象
UsernamePasswordToken token = new UsernamePasswordToken(loginname, password);
// shiro验证看是否登录成功
try{
// shiro登录
Subject subject = SecurityUtils.getSubject();
subject.login(token);
// 根据loginname查询user
User user_session = userLoginService.findUserByLoginname(loginname);
session.setAttribute("user_session",user_session);
// 跳转到登录成功的页面
return "/jsp/index.jsp";
}catch (UnknownAccountException e){
// 登录失败,打印异常信息
log.error("用户名不存在");
}catch (LockedAccountException e){
log.error("账号被锁定");
}catch (IncorrectCredentialsException e){
log.error("密码错误");
}catch (AuthenticationException e) {
// 其他认证异常
log.error("登录失败");
}
model.addAttribute("msg","用户名或者密码错误!");
// 返回到登录页面
return "/jsp/loginForm.jsp";
}
// 3.首页显示
@RequestMapping("/welcome")
public String welcome(){
return "/jsp/welcome.jsp";
}
// 4.用户注册
@RequestMapping("/register/registCode")
public String registCode(){
System.out.println("用户注册");
return "/jsp/regist.jsp";
}
// 5.找回密码
@RequestMapping("/password/repassword")
public String repassword(){
System.out.println("找回密码!");
return "/jsp/findPwd.jsp";
}
@RequestMapping("/logOut")
public String logOut(HttpSession session){
// 从session中移除用户
session.removeAttribute("user_session");
// 让session失效
session.invalidate();
// 返回登录页面
return "/jsp/loginForm.jsp";
}
}
3.2自定义 realm类,进行认证,授权
package com.hrf.util;
import com.hrf.bean.User;
import com.hrf.service.UserLoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/*
自定义认证类
*/
@Slf4j
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserLoginService userLoginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.debug("开始授权---------");
//获取当前登录用户身份
String loginname = (String)principalCollection.getPrimaryPrincipal();
//关联数据库表,查找用户对应的角色、权限菜单
// 模拟数据
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("admin");
return info;
// return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
log.debug("开始认证....");
//认证方法
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取用户身份
String loginname = (String)token.getPrincipal();
// 获取密码凭证
//4.获取凭证 密码
char[] cs = (char[]) token.getCredentials();
String password = String.valueOf(cs);
//第一个参数 原码 第二个参数salt盐 第三个参数迭代次数
Md5Hash password1 = new Md5Hash(password,loginname,5);
System.out.println(password1);
//模拟数据,只有username等于admin,认为用户存在
User user = userLoginService.findUserByLoginname(loginname);
if (user!=null) {
return new SimpleAuthenticationInfo(loginname,
user.getPassword(),
ByteSource.Util.bytes(loginname),
getName());
}
return null;
}
}
注意:shiro的工作原理
一、Shiro运行流程
比如一个登陆流程:
1、首先调用Subject.login(token)进行登录,他会委托给SecurityManager
2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有就返回认证失败,有的话就继续执行操作。
二 .描述Shiro认证过程
1、应用程序代码调用 Subject.login 方法,传递创建好的包含终端用户的 Principals(身份)和 Credentials(凭证)的 AuthenticationToken 实例;
2、Subject 实例委托应用程序的 SecurityManager 通过调用securityManager.login(token) 开始真正的验证;Subject 实例(通常为 DelegatingSubject或它的子类)
3、SubjectManager 接收 token,调用内部的 Authenticator 实例调用 authenticator.authenticate(token).Authenticator 通常是一个 ModularRealmAuthenticator 实例, 支持在身份验证中协调一个或多个Realm 实例;
4、如果应用程序中配置了一个以上的 Realm, ModularRealmAuthenticator 实例将利用配置好的AuthenticationStrategy 来启动 Multi-Realm 认证尝试。在Realms 被身份验证调用之前、调用期间、调用之后,AuthenticationStrategy 被调用使其能够对每个Realm 的结果作出反应。(AuthenticationStrategy都会被调用,对每个Realm 的结果作出反应);
5、每个配置的 Realm 用来帮助看它是否支持提交的 AuthenticationToken. 如果支持, 那么支持 Realm 的 getAuthenticationInfo 方法将会伴随着提交的 token 被调用. getAuthenticationInfo 方法有效地代表一个特定 Realm 的单一的身份验证尝试。
三、如何配置在 Spring 中配置使用 Shiro
1 , 在 web.xml 中配置 Shiro 的 Filter;
2、在 Spring 的配置文件中配置 Shiro;
3、配置自定义 Realm:实现自定义认证和授权;
4、配置 Shiro 实体类使用的缓存策略;
5、配置 SecurityManager;
6、配置保证 Shiro 内部 Bean 声明周期都得到执行的 Lifecycle Bean 后置处理器;
4 .关于搜索进行模糊查询,分页,查询列表最好写在一个controller中
4.1 前端要写路径
4.1.1 index.jsp前端界面
<li>
<a href="javascript:;">
<i class="iconfont"></i>
<cite>下载中心</cite>
<i class="iconfont nav_right"></i>
</a>
<ul class="sub-menu">
<li>
<a _href="${pageContext.request.contextPath}/document/list">
<i class="iconfont"></i>
<cite>文档查询</cite>
</a>
</li>
<li id="document">
<a _href="${pageContext.request.contextPath}/document/toadd">
<i class="iconfont"></i>
<cite>上传文档</cite>
</a>
</li>
</ul>
</li>
4.1.2 list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fkjava" uri="/pager-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文档信息</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
<link rel="shortcut icon" href="${pageContext.request.contextPath}/public/logo.ico" type="image/x-icon" />
<link rel="stylesheet" href="${pageContext.request.contextPath}/public/css/font.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/public/css/xadmin.css">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/public/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/public/js/xadmin.js"></script>
<script type="text/javascript">
$(function(){
/** 下载文档功能 */
$("a[id^='down_']").click(function(){
/** 得到需要下载的文档的id */
var id = this.id.replace("down_","");
/** 下载该文档 */
window.location = "${pageContext.request.contextPath}/document/downLoad?id="+id;
})
})
</script>
<script type="text/javascript">
$(function(){
if(${count}!=0){
$("#count1").hide();
$("#count2").show();
}
var username = "${sessionScope.user_session.loginname}";
if(username=="admin"||username=="manager"){
$("#aaa").show();
$("#bbb").show();
$("#do").css("display", "block");
$("#ID").css("display", "block");
$('tr').find('td:eq(0)').show();
$('tr').find('td:eq(8)').show();
}else{
$("#aaa").hide();
$("#bbb").hide();
$("#do").css("display", "none");
$("#ID").css("display", "none");
$('tr').find('td:eq(8)').hide();
};
})
</script>
</head>
<body>
<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
<a>
<cite>文档信息</cite></a>
</span>
<button id="aaa" type="button" οnclick="location.href='${pageContext.request.contextPath}/document/toadd'" class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:innert;margin-left:75%;;" lay-submit="" lay-filter="sreach"><i class="layui-icon"></i>增加</button>
<a id="bbb" class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" href="${pageContext.request.contextPath}/document/list" title="刷新">
<i class="layui-icon" style="line-height:30px">ဂ</i></a>
</div>
<div class="x-body">
<div class="layui-row" style="" align="center">
<form class="layui-form layui-col-md12 x-so" method="get" action="${pageContext.request.contextPath}/document/list">
<input type="text" name="content" style="width:50%;" placeholder="请输入查找内容" autocomplete="off" class="layui-input">
<button class="layui-btn" lay-submit="" lay-filter="sreach"><i class="layui-icon"></i></button>
</form>
</div>
<table class="layui-table">
<thead>
<tr>
<th>
<div class="layui-unselect header layui-form-checkbox" lay-skin="primary"><i class="layui-icon"></i></div>
</th>
<th>ID</th>
<th>标题</th>
<th>描述</th>
<th>文件名</th>
<th>发布日期</th>
<th>发布用户</th>
<th>下载</th>
<th id="do">操作</th>
</thead>
<tbody>
<c:forEach items="${requestScope.list}" var="document" varStatus="stat">
<tr>
<td>
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" data-id='2'><i class="layui-icon"></i></div>
</td>
<td>${document.id}</td>
<td>${document.title }</td>
<td>${document.remark }</td>
<td>${document.filename }</td>
<td>${document.createdate}</td>
<td>${document.user.username }</td>
<td align="center" width="40px;"><a href="#" id="down_${document.id }">
<img width="20" height="20" title="下载" src="${pageContext.request.contextPath}/public/images/downLoad.png"/></a>
</td>
<td class="td-manage">
<a title="编辑" href='${pageContext.request.contextPath}/document/toedit?id=${document.id}'>
<i class="layui-icon"></i>
</a>
<a title="删除" οnclick="member_del(this,'${document.id }')" href="javascript:;">
<i class="layui-icon"></i>
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- 分页标签 -->
<div style="margin-left: 400px;" id="count1">
<fkjava:pager
pageIndex="${requestScope.pageModel.pageIndex}"
pageSize="${requestScope.pageModel.pageSize}"
recordCount="${requestScope.pageModel.recordCount}"
style="digg"
submitUrl="${pageContext.request.contextPath}/document/list?pageIndex={0}"/>
</div>
<div style="margin-left: 500px; display: none;" id="count2">
<p style="color: rgb(0,97,222)">共查询到<font color="red">${count}</font>条数据</p>
</div>
</div>
<script>
/*用户-删除*/
function member_del(obj,id){
layer.confirm('确认要删除吗?',function(index){
//发异步删除数据
//等以后再使用异步,这里先使用
$.get("${pageContext.request.contextPath}/document/delete?id="+id);
$(obj).parents("tr").remove();
layer.msg('已删除!',{icon:1,time:1000});
location.reload();
});
}
function delAll (argument) {
var data = tableCheck.getData();
layer.confirm('确认要删除吗?'+data,function(index){
//捉到所有被选中的,发异步进行删除
layer.msg('删除成功', {icon: 1});
$(".layui-form-checked").not('.header').parents('tr').remove();
});
}
</script>
</body>
</html>
4.2 controller层编写
package com.hrf.controller;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hrf.bean.Document;
import com.hrf.service.DocumentService;
import com.hrf.util.PageModel;
import com.hrf.util.UTF8String;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.jws.WebParam;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Controller
@RequestMapping("/document")
public class DocumentController {
@Autowired
private DocumentService documentService;
@RequestMapping("/list")
public String list(@RequestParam(name = "pageIndex",defaultValue = "1") Integer pageIndex,
@RequestParam(name = "content",defaultValue = "") String content,
PageModel pageModel,
Model model){
PageHelper.startPage(pageIndex,5);
List<Document> documentList = documentService.findDocumentList(content);
// 这是一个分页类
PageInfo pageInfo = new PageInfo(documentList);
List list = pageInfo.getList();
pageModel.setPageIndex(pageIndex);
pageModel.setRecordCount((int) pageInfo.getTotal());
model.addAttribute("list",list);
model.addAttribute("pageModel",pageModel);
return "/jsp/document/list.jsp";
}
}
4.3service层接口和实现类
4.3.1 接口
package com.hrf.service;
import com.hrf.bean.Document;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface DocumentService {
List<Document> findDocumentList(String content);
}
4.3.2 实现类
package com.hrf.service;
import com.hrf.bean.Document;
import com.hrf.mapper.DocumentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DocumentServiceImpl implements DocumentService{
@Autowired
private DocumentMapper documentMapper;
@Override
public List<Document> findDocumentList(String content) {
return documentMapper.selectAll(content);
}
}
4.4 mapper接口 和sql语句
4.4.1mapper接口
package com.hrf.mapper;
import com.hrf.bean.Document;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface DocumentMapper {
int deleteByPrimaryKey(Integer id);
}
4.4.2sql语句的实现
<resultMap id="BaseResultMap" type="com.hrf.bean.Document">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="title" jdbcType="VARCHAR" property="title" />
<result column="filename" jdbcType="VARCHAR" property="filename" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="createdate" jdbcType="TIMESTAMP" property="createdate" />
<result column="user_id" jdbcType="INTEGER" property="userId" />
<association property="user" javaType="User" autoMapping="true"/>
</resultMap>
<select id="selectAll" resultMap="BaseResultMap">
select d.id, title, filename, remark, d.createdate, d.user_id,u.username
from document_inf d
left join user_inf u on d.user_id=u.id
<where>
<if test="content!=null">
title like '%' #{content} '%'
</if>
</where>
</select>
4.5实现类
package com.hrf.bean;
import java.util.Date;
public class Document {
private Integer id;
private String title;
private String filename;
private String remark;
private Date createdate;
private Integer userId;
//关联关系一对一
private User user;
//也可以传入属性,但是最好传入属性
//private String username;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title == null ? null : title.trim();
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename == null ? null : filename.trim();
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark == null ? null : remark.trim();
}
public Date getCreatedate() {
return createdate;
}
public void setCreatedate(Date createdate) {
this.createdate = createdate;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
5. 不借助自定义标签实现分页
5.1controller层
@RequestMapping("/list")
public String list(@RequestParam(name = "page",defaultValue = "1") Integer page,
@RequestParam(name = "size",defaultValue = "5") Integer size,
@RequestParam(name = "content",defaultValue = "") String content,
HttpServletRequest request){
List<Employee> employeeList = employeeService.findEmployeeAll(page,size,content);
PageInfo pageInfos = new PageInfo(employeeList);
request.setAttribute("pageInfos",pageInfos);
return "/jsp/employee/list.jsp";
}
5.2service层实现类
@Override
public List<Employee> findEmployeeAll(@Param("page") Integer page,
@Param("size") Integer size,
@Param("content") String content) {
PageHelper.startPage(page,size);
return employeeMapper.selectAll2(content);
}
5.3 mapper里面的sql语句
<select id="selectAll2" resultMap="BaseResultMap">
select e.id, e.dept_id, e.job_id, e.name ename, e.card_id, e.address, e.phone, e.sex_id, e.education_id,
e.createdate, e.user_id, u.id uid, u.username , u.email,j.name jname, d.name dname, ed.name edname ,s.name sexname
from employee_inf e left join user_inf u on e.user_id=u.id
left join job_inf j on e.job_id=j.id
left join dept_inf d on e.dept_id=d.id
left join education_inf ed on e.education_id=ed.id
LEFT JOIN sex_inf s ON e.sex_id = s.id
<where>
<if test="content!=null">
or e.name like '%' #{content} '%'
</if>
<if test="content!=null">
or e.address like '%' #{content} '%'
</if>
<if test="content!=null">
or u.username like '%' #{content} '%'
</if>
<if test="content!=null">
or j.name like '%' #{content} '%'
</if>
<if test="content!=null">
or d.name like '%' #{content} '%'
</if>
<if test="content!=null">
or ed.name like '%' #{content} '%'
</if>
</where>
</select>
<resultMap id="BaseResultMap" type="com.hrf.bean.Employee">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="dept_id" jdbcType="INTEGER" property="deptId" />
<result column="job_id" jdbcType="INTEGER" property="jobId" />
<result column="ename" jdbcType="VARCHAR" property="name" />
<result column="card_id" jdbcType="VARCHAR" property="cardId" />
<result column="address" jdbcType="VARCHAR" property="address" />
<result column="phone" jdbcType="VARCHAR" property="phone" />
<result column="sex_id" jdbcType="INTEGER" property="sexId" />
<result column="education_id" jdbcType="INTEGER" property="educationId" />
<result column="createdate" jdbcType="TIMESTAMP" property="createdate" />
<result column="user_id" jdbcType="INTEGER" property="userId" />
<association property="user" javaType="User" autoMapping="true">
</association>
<association property="job" javaType="Job" autoMapping="true">
<result property="name" column="jname"/>
</association>
<association property="dept" javaType="Dept" autoMapping="true">
<result property="name" column="dname"/>
</association>
<association property="education" javaType="Education" autoMapping="true">
<result property="name" column="edname"/>
</association>
<association property="sex" javaType="Sex" autoMapping="true">
<result property="name" column="sname"/>
</association>
</resultMap>
5.4前端实现
5.4.1jsp代码
<link rel="stylesheet" href="${pageContext.request.contextPath}/public/css/myPage.css">
<c:forEach items="${requestScope.pageInfos.list}" var="employee" varStatus="stat">
<tr>
<td>
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" data-id='2'><i class="layui-icon"></i></div>
</td>
<td>${employee.name }</td>
<td>${employee.user.username}</td> <!--方便知道谁和谁关联 -->
<td>
<c:choose>
<c:when test="${employee.sexId==1}">男</c:when>
<c:otherwise><font>女</font></c:otherwise>
</c:choose>
</td>
<td>${employee.phone }</td>
<td>${employee.user.email }</td>
<td>${employee.job.name }</td>
<td>${employee.dept.name }</td>
<td>${employee.education.name }</td>
<td>${employee.cardId }</td>
<td>${employee.address }</td>
<td>${employee.createdate}</td>
<td class="td-manage">
<a title="编辑" href='${pageContext.request.contextPath}/employee/toedit?id=${employee.id}'>
<i class="layui-icon"></i>
</a>
<a title="删除" οnclick="member_del(this,'${employee.id}')" href="javascript:;">
<i class="layui-icon"></i>
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- 分页标签 -->
<div style="margin-left: 400px;" id="count1">
<ul class="pagination modal-1">
<li><a href="${pageContext.request.contextPath}/employee/list?page=1&size=5" class="pre">首页</a></li>
<c:if test="${pageInfos.pageNum==1}">
<li><a href="${pageContext.request.contextPath}/employee/list?page=1&size=5" class="prev">上一页</a></li>
</c:if>
<c:if test="${pageInfos.pageNum!=1}">
<li><a href="${pageContext.request.contextPath}/employee/list?page=${pageInfos.pageNum-1}&size=5" class="prev">上一页</a></li>
</c:if>
<c:forEach begin="1" end="${pageInfos.pages}" var="pageNumber">
<li><a href="${pageContext.request.contextPath}/employee/list?page=${pageNumber}&size=5" class="active">${pageNumber}</a></li>
</c:forEach>
<c:if test="${pageInfos.pageNum!=pageInfos.pages}">
<li><a href="${pageContext.request.contextPath}/employee/list?page=${pageInfos.pageNum+1}&size=5" class="next">下一页</a></li>
</c:if>
<c:if test="${pageInfos.pageNum==pageInfos.pages}">
<li><a href="${pageContext.request.contextPath}/employee/list?page=${pageInfos.pages}&size=5" class="next">下一页</a></li>
</c:if>
<li><a href="${pageContext.request.contextPath}/employee/list?page=${pageInfos.pages}&size=5" class="next">尾页</a></li>
</ul>
</div>
5.4.2 css代码给他样式
.pagination {
list-style: none;
display: inline-block;
padding: 0;
margin-top: 10px;
}
.pagination li {
display: inline;
text-align: center;
}
.pagination a {
float: left;
display: block;
font-size: 14px;
text-decoration: none;
padding: 5px 12px;
color: #fff;
margin-left: -1px;
border: 1px solid transparent;
line-height: 1.5;
}
.pagination a.active {
cursor: default;
}
.pagination a:active {
outline: none;
}
.modal-1 li:first-child a {
-moz-border-radius: 6px 0 0 6px;
-webkit-border-radius: 6px;
border-radius: 6px 0 0 6px;
}
.modal-1 li:last-child a {
-moz-border-radius: 0 6px 6px 0;
-webkit-border-radius: 0;
border-radius: 0 6px 6px 0;
}
.modal-1 a {
border-color: #ddd;
color: #4285F4;
background: #fff;
}
.modal-1 a:hover {
background: #eee;
}
.modal-1 a.active, .modal-1 a:active {
border-color: #4285F4;
background: #4285F4;
color: #fff;
}
5.6最后分页的结果样式
6.文件的上传与下载
6.1 文件的上传
6.1.1 前端页面的实现必须有三点
(1):上传文件是上传到服务器上,而保存到数据库是文件名
(2):上传文件是以文件转换为二进制流的形式上传的
(3): enctype="multipart/form-data"需要设置在form里面,否则无法提交文件
</head>
<body>
<div class="x-body">
<form class="layui-form" method="POST" id="deptForm" enctype="multipart/form-data" action="${pageContext.request.contextPath}/document/add">
<input type="hidden" name="id" id="id" value="${document.id }" >
<input type="hidden" name="userId" id="user_id" value="${sessionScope.user_session.id}" >
<div class="layui-form-item">
<label for="username" class="layui-form-label">
<span class="x-red">*</span>标题
</label>
<div class="layui-input-inline">
<input type="text" id="title" name="title" required="" lay-verify="required"
placeholder="不少于3个汉字" autocomplete="off" class="layui-input" value="${document.title }">
</div>
</div>
<div class="layui-form-item">
<label for="username" class="layui-form-label">
<span class="x-red">*</span>描述
</label>
<div class="layui-input-inline">
<input type="text" id="remark" name="remark" required="" lay-verify="required"
placeholder="不少于5个汉字" autocomplete="off" class="layui-input" value="${document.remark }">
</div>
</div>
<div class="layui-form-item">
<label for="username" class="layui-form-label">
<span class="x-red">*</span>上传文件
</label>
<div class="layui-input-inline">
<input type="file" id="file" name="file" >
<p class="x-red">必须选择上传文件</p>
<p class="x-red">${param.message}</p>
</div>
</div>
<div class="layui-form-item">
<label for="L_repass" class="layui-form-label">
</label>
<input type="submit" value=" 提交" class="layui-btn" lay-filter="add" lay-submit=""/>
</div>
</form>
</div>
</body>
</html>
6.1.2 controller层方法实现
进行新增操作,文件上传
@RequestMapping("/add")
public String add(Document document,
@RequestParam("file") MultipartFile multipartFile,
HttpServletRequest request) throws ParseException, IOException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
document.setCreatedate(df.parse(df.format(new Date())));
// 进行上传文档
// 获取文件上传到具体文件夹的绝对路径
String realpath = request.getSession().getServletContext().getRealPath("/upload/");
// 获取上传的文件名
String fileName = multipartFile.getOriginalFilename();
//为了确保上传文件的重名问题,对文件名进行处理
fileName = UUID.randomUUID().toString() +"_"+ fileName;
// 根据路径构建文件对象
// 在构建过程中一定要注意路径问题
File uploadFile = new File(realpath, fileName);
// 判断指定文件夹uploadfiles是否存在,不存在就创建
if (!uploadFile.exists()) {
uploadFile.mkdirs();
}
// 上传文件
multipartFile.transferTo(uploadFile);
document.setFilename(fileName);
documentService.addDocument(document);
return "redirect:/document/list";
}
6.2文件的下载
// 文件下载
@RequestMapping("/downLoad")
public String downLoad(HttpServletRequest request,
HttpServletResponse response,
Integer id) throws IOException {
// 获取文件名
Document document = documentService.findDocumentById(id);
String filename = document.getFilename();
// 获取下载的文件路径
String realpath = request.getSession().getServletContext().getRealPath("/WEB-INF/files/");
// 设置下载文件时的响应报头
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename=" + UTF8String.toUTF8String(filename));
// 获取文件输入流
FileInputStream in = new FileInputStream(new File(realpath, filename));
// 获得响应对象的输出流,用于向客户端输出二进制数据
ServletOutputStream out = response.getOutputStream();
out.flush();
int aRead = 0;
byte[] b = new byte[1024];
// 写到响应输出流
while ((aRead = in.read(b)) != -1 && in != null) {
out.write(b, 0, aRead);
}
out.flush();
// 关闭IO对象
in.close();
out.close();
return "redirect:/document/list";
}
/**
* 下载时保存中文文件名的字符编码转换方法
*/
public String toUTF8String(String str) {
StringBuffer sb = new StringBuffer();
int len = str.length();
for (int i = 0; i < len; i++) {
// 取出字符串中的每个字符
char c = str.charAt(i);
// Unicode码值为0-255时,不作处理
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
// 转换成utf-8编码
byte[] b;
try {
b = Character.toString(c).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO: handle exception
e.printStackTrace();
b = null;
}
// 转换为%HH的字符串形式
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0) {
k &= 255;
}
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
7. 批量添加人员(以员工为例)
7.1批量工具类
package com.hrf.util;
import com.hrf.bean.Employee;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
public class ExcelData {
private XSSFSheet sheet;
/**
* 构造函数,初始化excel数据
* @param filePath excel路径
* @param sheetName sheet表名
*/
public ExcelData(String filePath, String sheetName){
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(filePath);
XSSFWorkbook sheets = new XSSFWorkbook(fileInputStream);
//获取sheet
sheet = sheets.getSheet(sheetName);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据行和列的索引获取单元格的数据
* @param row
* @param column
* @return
*/
public String getExcelDateByIndex(int row,int column){
XSSFRow row1 = sheet.getRow(row);
String cell = row1.getCell(column).toString();
return cell;
}
/**
* 根据某一列值为“******”的这一行,来获取该行第x列的值
* @param caseName
* @param currentColumn 当前单元格列的索引
* @param targetColumn 目标单元格列的索引
* @return
*/
public String getCellByCaseName(String caseName,int currentColumn,int targetColumn){
String operateSteps="";
//获取行数
int rows = sheet.getPhysicalNumberOfRows();
for(int i=0;i<rows;i++){
XSSFRow row = sheet.getRow(i);
String cell = row.getCell(currentColumn).toString();
if(cell.equals(caseName)){
operateSteps = row.getCell(targetColumn).toString();
break;
}
}
return operateSteps;
}
//打印excel数据
public void readExcelData(){
//获取行数
int rows = sheet.getPhysicalNumberOfRows();
for(int i=0;i<rows;i++){
//获取列数
XSSFRow row = sheet.getRow(i);
int columns = row.getPhysicalNumberOfCells();
for(int j=0;j<columns;j++){
String cell = row.getCell(j).toString();
System.out.println(cell);
}
}
}
//获取长度
public int len(String file){
ExcelData sheet1 = new ExcelData(file, "Sheet1");
int i=0;
while (true){
try {
String c=sheet1.getExcelDateByIndex(i,0);
i++;
}catch (NullPointerException e){
break;
}
}
return i;
}
//测试方法
public static void main(String[] args){
}
//读取对象
public List<Employee> employeeList(String file){
ExcelData excelData=new ExcelData(file,"Sheet1");
int i=excelData.len(file);
//System.out.println(i);
List<Employee> list=new ArrayList<>();
for(int j=1;j<i;j++){
String id=excelData.getExcelDateByIndex(j,0);
String dept_id=excelData.getExcelDateByIndex(j,1);
String job_id=excelData.getExcelDateByIndex(j,2);
String name=excelData.getExcelDateByIndex(j,3);
String card_id=excelData.getExcelDateByIndex(j,4);
String address=excelData.getExcelDateByIndex(j,5);
String phone=excelData.getExcelDateByIndex(j,6);
String sex_id=excelData.getExcelDateByIndex(j,7);
String education_id=excelData.getExcelDateByIndex(j,8);
Employee employee=new Employee();
employee.setId(Integer.parseInt(id));
employee.setDeptId(Integer.parseInt(dept_id));
employee.setJobId(Integer.parseInt(job_id));
employee.setName(name);
employee.setCardId(card_id);
employee.setAddress(address);
employee.setPhone(phone);
employee.setSexId(Integer.parseInt(sex_id));
employee.setEducationId(Integer.parseInt(education_id));
list.add(employee);
}
return list;
}
}
7.2 controller层方法
// 进行批量加入
@RequestMapping("/piliang")
public String piliang(@RequestParam("file") MultipartFile file,
HttpServletRequest req,
Model model) throws IOException {
// 需要设计到文件的上传与下载
String fileName= file.getName();
String uploadPath= WebUtils.getRealPath(req.getSession().getServletContext(),"/upload/");
String path= uploadPath+ new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + fileName;
file.transferTo(new File(path));
ExcelData excelData=new ExcelData(path,"sheet1");
List<Employee> list=excelData.employeeList(path);
int i=employeeService.pladd(list);
if (i!=0){
model.addAttribute("message","ok");
}else {
model.addAttribute("message","error");
}
return "redirect:/employee/list";
}
8 数据可视化
8.1数据可视化工具类
package com.hrf.util;
public class ChartsVo {
private String name;
private Integer value;
private Integer mailmarketing;
private Integer allianceadvertising;
private Integer videoadvertising;
private Integer directaccess;
private Integer searchengine;
public Integer getMailmarketing() {
return mailmarketing;
}
public void setMailmarketing(Integer mailmarketing) {
this.mailmarketing = mailmarketing;
}
public Integer getAllianceadvertising() {
return allianceadvertising;
}
public void setAllianceadvertising(Integer allianceadvertising) {
this.allianceadvertising = allianceadvertising;
}
public Integer getVideoadvertising() {
return videoadvertising;
}
public void setVideoadvertising(Integer videoadvertising) {
this.videoadvertising = videoadvertising;
}
public Integer getDirectaccess() {
return directaccess;
}
public void setDirectaccess(Integer directaccess) {
this.directaccess = directaccess;
}
public Integer getSearchengine() {
return searchengine;
}
public void setSearchengine(Integer searchengine) {
this.searchengine = searchengine;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public ChartsVo() {
}
public ChartsVo(String name, Integer value) {
this.name = name;
this.value = value;
}
}
8.2controller层中的方法
package com.hrf.controller;
import com.hrf.service.EmployeeService;
import com.hrf.util.ChartsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class StatisticsController {
@Autowired
private EmployeeService employeeService;
// 进行数据可视化
@RequestMapping("/statistics")
public String statistics(){
return "/jsp/statistics/statistics.jsp";
}
//获取男女比例个数
@RequestMapping("/echartsData")
@ResponseBody
public List<ChartsVo> echartsData() {
List<ChartsVo> list= employeeService.getSexCount();
return list;
}
//获取各个职位的员工个数
@RequestMapping("/echartsData1")
@ResponseBody
public List<ChartsVo> echartsData1() {
List<ChartsVo> list= employeeService.getJobCount();
return list;
}
//获取一周处理的业务的类型的个数
@RequestMapping("/echartsData2")
@ResponseBody
public List<ChartsVo> echartsData2() {
List<ChartsVo> list= employeeService.getBusinessCount();
return list;
}
//获取各个员工居住地址的个数
@RequestMapping("/echartsData3")
@ResponseBody
public List<ChartsVo> echartsData3() {
List<ChartsVo> list= employeeService.getAddressCount();
return list;
}
}
8.3service层实现类中的方法
//获取男女比例个数
@Override
public List<ChartsVo> getSexCount() {
List<ChartsVo> list = new ArrayList<>();
int male = employeeMapper.selectByMale();
ChartsVo maleChartsVo = new ChartsVo("男性",male);
list.add(maleChartsVo);
int female = employeeMapper.selectByFemale();
ChartsVo femaleChartsVo = new ChartsVo("女性",female);
list.add(femaleChartsVo);
return list;
}
//获取各个职位的员工个数
@Override
public List<ChartsVo> getJobCount() {
return employeeMapper.getJobCount();
}
//获取一周处理的业务的类型的个数
@Override
public List<ChartsVo> getBusinessCount() {
return employeeMapper.getBusinessCount();
}
//获取各个员工居住地址的个数
@Override
public List<ChartsVo> getAddressCount() {
return employeeMapper.getAddressCount();
}
8.4mapper里面的sql语句
<!-- 查询员工性别为男性的数目-->
<select id="selectByMale" resultType="int">
select count(*) from employee_inf e ,sex_inf s where e.sex_id=s.id and s.name= '男'
</select>
<!-- 查询员工性别为女性的数目-->
<select id="selectByFemale" resultType="int">
select count(*) from employee_inf e ,sex_inf s where e.sex_id=s.id and s.name= '女'
</select>
<!-- 查询各个职位员工的个数-->
<select id="getJobCount" resultType="com.hrf.util.ChartsVo">
select count(e.job_id) value,j.name from employee_inf e join job_inf j on e.job_id=j.id group by e.job_id
</select>
<!-- 获取一周处理的业务的类型的个数-->
<select id="getBusinessCount" resultType="com.hrf.util.ChartsVo">
select * from business_inf
</select>
<!-- 获取各个员工居住地址的个数-->
<select id="getAddressCount" resultType="com.hrf.util.ChartsVo">
select count(*) value ,address name from employee_inf group by address
</select>
标签:总结,return,String,人事,int,管理系统,id,import,public 来源: https://blog.csdn.net/weixin_43447266/article/details/121665687