CMS项目介绍
项目的主要功能:包含后台图片管理,后台职位管理,用户登录,用户注册,用户邮箱激活,前台展示,用户登录,高级查询。
项目的主要技术:
web框架spring+springmvc+springjdbc
前端框架:bootstrap
职位和轮播图的CRUD
分页对象—显示职位和轮播管理信息
富文本编辑器wangeditor—优化相关展示信息
页面静态化技术freemarker—优化访问服务器过多,效率低
缓存技术ehcache----优化访问服务器过多,效率低
高级查询技术—简单提供职位的精确查询
邮箱激活技术
Spring拦截器—后台访问安全
开发工具:eclipse
服务器:Tomcat7.0.57
调试浏览器:火狐
数据库:mysql
1.采用maven项目结构:
![maven项目结构](https://img-blog.csdnimg.cn/20190223231042318.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYzNjI5MQ==,size_16,color_FFFFFF,t_70) 2.项目分层
dao层----数据层,与数据库做交互
service层---业务层,处理前台逻辑
web层---处理前台请求,返回页面
![项目分层](https://img-blog.csdnimg.cn/20190224224957765.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYzNjI5MQ==,size_16,color_FFFFFF,t_70)
3.项目配置
采用Spring+SpringMVC+Springjdbc
web.xml配置
cms
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
characterEncoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
characterEncoding
/*
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-servlet.xml
1
springmvc
/
SpringMVC——servlet配置
2000000000
applicationContext.xml配置
数据库的配置:db.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=
password=
缓存的配置:ehcache.xml
4.相关内容的实现
1.职位的CRUD
职位的CRUD使用Springjdbc+Springmvc
难点:地址的显示
需求:前端的地址需要由后台查询
思路:将地址封装,而jobs对象只存储地址的编号,数据库专门建立地址表,并提供职位与地址的视图查询
package cn.xxx.domain;
/**
* @author peng
*存储工作地址的字段
*/
public class Address {
//地址的id
private Long address_id;
//地址的名字
private String address;
//父id
private Integer pid;
@Override
public String toString() {
return "Address [address_id=" + address_id + ", address=" + address + ", pid=" + pid + "]";
}
public Address() {
super();
// TODO Auto-generated constructor stub
}
public Long getAddress_id() {
return address_id;
}
public void setAddress_id(Long address_id) {
this.address_id = address_id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public Address(Long address_id, String address, Integer pid) {
super();
this.address_id = address_id;
this.address = address;
this.pid = pid;
}
}
domain层:
package cn.itsource.domain;
import java.io.Serializable;
import java.util.Date;
/**
* @author peng
*工作类
*/
public class Jobs implements Serializable{
//工作的编号
private Integer id;
//工作标题
private String title;
//多表查询的address
private String address;
//工作地址编号
private Long address_id;
//招聘人数
private Integer jobnum;
//薪资
private Integer treatment;
//工作描述
private String describes;
//工作要求
private String requires;
private String htmlurl;
//工作类型:全职or兼职
private Integer positiontype;
//是否启用
private Boolean isenabled;
//上传时间
private Date inputdate=new Date();
public Jobs() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Jobs [id=" + id + ", title=" + title + ", address=" + address + ", address_id=" + address_id
+ ", jobnum=" + jobnum + ", treatment=" + treatment + ", describes=" + describes + ", requires="
+ requires + ", htmlurl=" + htmlurl + ", positiontype=" + positiontype + ", isenabled=" + isenabled
+ ", inputdate=" + inputdate + "]";
}
public Jobs(Integer id, String title, String address, Long address_id, Integer jobnum, Integer treatment,
String describes, String requires, String htmlurl, Integer positiontype, Boolean isenabled,
Date inputdate) {
super();
this.id = id;
this.title = title;
this.address = address;
this.address_id = address_id;
this.jobnum = jobnum;
this.treatment = treatment;
this.describes = describes;
this.requires = requires;
this.htmlurl = htmlurl;
this.positiontype = positiontype;
this.isenabled = isenabled;
this.inputdate = inputdate;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getAddress_id() {
return address_id;
}
public void setAddress_id(Long address_id) {
this.address_id = address_id;
}
public Integer getJobnum() {
return jobnum;
}
public void setJobnum(Integer jobnum) {
this.jobnum = jobnum;
}
public Integer getTreatment() {
return treatment;
}
public void setTreatment(Integer treatment) {
this.treatment = treatment;
}
public String getDescribes() {
return describes;
}
public void setDescribes(String describes) {
this.describes = describes;
}
public String getRequires() {
return requires;
}
public void setRequires(String requires) {
this.requires = requires;
}
public String getHtmlurl() {
return htmlurl;
}
public void setHtmlurl(String htmlurl) {
this.htmlurl = htmlurl;
}
public Integer getPositiontype() {
return positiontype;
}
public void setPositiontype(Integer positiontype) {
this.positiontype = positiontype;
}
public Boolean getIsenabled() {
return isenabled;
}
public void setIsenabled(Boolean isenabled) {
this.isenabled = isenabled;
}
public Date getInputdate() {
return inputdate;
}
public void setInputdate(Date inputdate) {
this.inputdate = inputdate;
}
}
dao层:
package cn.xxx.dao;
import java.util.List;
import cn.xxx.domain.Images;
import cn.xxx.domain.Jobs;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
public interface IJobsDao {
/**显示全部职位*/
List queryAll();
/**添加职位*/
void add(Jobs job);
/**删除职位 通过id*/
void delete(Long id);
/**查询某个职位 通过id*/
Jobs queryOne(Long id);
/**分页查询*/
PageList queryByPage(SqlCondition sqlCondition);
/**更新某个职位 通过id*/
void update(Jobs job);
/**高级查询*/
List queryByCondition(SqlCondition sqlCondition);
}
Service层
package cn.xxx.service;
import java.util.List;
import cn.xxx.domain.Images;
import cn.xxx.domain.Jobs;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
public interface IJobsService {
List queryAll();
void add(Jobs job);
void delete(Long id);
Jobs queryOne(Long id);
/**分页查询*/
PageList queryByPage(SqlCondition sqlCondition);
/**更新*/
void update(Jobs job);
/**高级查询*/
List queryByCondition(SqlCondition sqlCondition);
}
package cn.xxx.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.xxx.dao.IJobsDao;
import cn.xxx.domain.Jobs;
import cn.xxx.myutils.CacheUtils;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
import cn.xxx.service.IJobsService;
import net.sf.ehcache.CacheManager;
@Service
public class JobsServiceImpl implements IJobsService {
/**用来判断是否需要新增缓存 默认为flase不需要缓存
* 新增 删除 修改 需要更新缓存
*
* */
private Boolean isEnableCache=false;
@Autowired
private IJobsDao jobsDaoImpl;
@Override
public List queryAll() {
return jobsDaoImpl.queryAll();
}
@Override
public void add(Jobs Jobs) {
jobsDaoImpl.add(Jobs);
isEnableCache=true;
}
@Override
public void delete(Long id) {
jobsDaoImpl.delete(id);
isEnableCache=true;
}
@Override
public Jobs queryOne(Long id) {
return jobsDaoImpl.queryOne(id);
}
@Override
public PageList queryByPage(SqlCondition sqlCondition) {
PageList queryByPage = null;
//创建缓存管理者
CacheManager cacheManager = CacheManager.create();
//每次不同的存入key
String key="key_"+sqlCondition.getCurrentPage();
//缓存名称
String cacheName="jobsCache";
if(sqlCondition.getTitle()!=null&&!"".equals(sqlCondition.getTitle())){
/**
* 使用高级查询 将缓存重新清理
*/
sqlCondition.setIsEnableCache(true);
}
if(sqlCondition.getPositiontype()!=null&&!"".equals(sqlCondition.getPositiontype())&&sqlCondition.getPositiontype()!=2){
sqlCondition.setIsEnableCache(true);
}
//静态化操作
/**取出缓存*/
queryByPage = (PageList) CacheUtils.getCacheData(cacheManager, key, cacheName);
/**如果未取出数据,进行查询存储数据到缓存*/
if(queryByPage==null||isEnableCache||sqlCondition.getIsEnableCache()){
//如果标识符为ture表名内容已修改需要更新缓存
if(isEnableCache){
//删除原来缓存数据
cacheManager.getCache(cacheName).removeAll();
}
queryByPage = jobsDaoImpl.queryByPage(sqlCondition);
CacheUtils.setCacheData(cacheManager, key, queryByPage, cacheName);
isEnableCache=false;
}
return queryByPage;
}
@Override
public void update( Jobs job) {
// TODO Auto-generated method stub
jobsDaoImpl.update(job);
isEnableCache=true;
}
@Override
public List queryByCondition(SqlCondition sqlCondition) {
// TODO Auto-generated method stub
return jobsDaoImpl.queryByCondition(sqlCondition);
}
}
2.轮播图的CRUD
难点:图片的上传和删除
需求:用户可以自己上传图片到后台,选择是否在显示
思路:在前台提交的form表单设置图片属性,图片对象提供图片这个对象,在上传的时候,在服务器目录下存储图片,同时随机生成文件名(防止文件名重复),而在数据库保存图片名称和相对路径,绝对路径通过请求对象拿到,取出和删除都通过构建含有路径和文件名的文件对象来删除,注意删除要调用gc释放资源
domian:
package cn.xxx.domain;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
public class Images {
/**图片名称*/
private String imagesName;
/**图片id*/
private Long id;
/**图片信息*/
private String info;
/**图片上传日期*/
private Date imagesDate;
/**图片是否启用*/
private Boolean imagesIsEnable;//true是启用
/**图片地址*/
private String storePath;
/**图片存储对象*/
private MultipartFile multiPartFile;
public Images() {
super();
// TODO Auto-generated constructor stub
}
public Images(String imagesName, Long id, String info, Date imagesDate, Boolean imagesIsEnable, String storePath,
MultipartFile multiPartFile) {
super();
this.imagesName = imagesName;
this.id = id;
this.info = info;
this.imagesDate = imagesDate;
this.imagesIsEnable = imagesIsEnable;
this.storePath = storePath;
this.multiPartFile = multiPartFile;
}
@Override
public String toString() {
return "Images [imagesName=" + imagesName + ", id=" + id + ", info=" + info + ", imagesDate=" + imagesDate
+ ", imagesIsEnable=" + imagesIsEnable + ", storePath=" + storePath + ", multiPartFile=" + multiPartFile
+ "]";
}
public String getImagesName() {
return imagesName;
}
public void setImagesName(String imagesName) {
this.imagesName = imagesName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Date getImagesDate() {
return imagesDate;
}
public void setImagesDate(Date imagesDate) {
this.imagesDate = imagesDate;
}
public Boolean getImagesIsEnable() {
return imagesIsEnable;
}
public void setImagesIsEnable(Boolean imagesIsEnable) {
this.imagesIsEnable = imagesIsEnable;
}
public String getStorePath() {
return storePath;
}
public void setStorePath(String storePath) {
this.storePath = storePath;
}
public MultipartFile getMultiPartFile() {
return multiPartFile;
}
public void setMultiPartFile(MultipartFile multiPartFile) {
this.multiPartFile = multiPartFile;
}
}
Dao:
package cn.xxx.dao;
import java.util.List;
import cn.xxx.domain.Images;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
public interface IImagesDao {
/**显示照片*/
List queryAll();
/**添加照片*/
void add(Images images);
/**删除照片*/
void delete(Long id);
/**查询一个*/
Images queryOne(Long id);
/**分页查询*/
PageList queryByPage(SqlCondition sqlCondition);
/**更新照片*/
void update(Images images);
}
package cn.xxx.dao.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import cn.xxx.dao.IImagesDao;
import cn.xxx.domain.Images;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
@Repository
public class ImagesDaoImpl implements IImagesDao{
//使用Spring的jdbc对象
@Autowired
private JdbcTemplate jdbcTemplate;
//查询所有的方法
@Override
public List queryAll() {
String sql="select * from t_images";
return this.jdbcTemplate.query(sql, new BeanPropertyRowMapper(Images.class));
}
//新增方法
@Override
public void add(Images images) {
String sql="insert into t_images(imagesName,info,imagesDate,imagesIsEnable,storePath)values(?,?,?,?,?)";
this.jdbcTemplate.update(sql,
images.getImagesName(),
images.getInfo(),
images.getImagesDate(),
images.getImagesIsEnable(),
images.getStorePath());
}
//删除方法
@Override
public void delete(Long id) {
String sql="delete from t_images where id=?";
this.jdbcTemplate.update(sql, id);
}
//查询一条方法
@Override
public Images queryOne(Long id) {
String sql="select * from t_images where id=?";
return this.jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Images.class), id);
}
//分页查询方法
@Override
public PageList queryByPage(SqlCondition sqlCondition) {
//分页查询所有条数
String countSql="select count(*) from t_images";
Integer totalCount = this.jdbcTemplate.queryForObject(countSql, Integer.class);
//当前页
Integer currentPage = sqlCondition.getCurrentPage();
//每页展示的数据条数
Integer pageSize = sqlCondition.getPageSize();
//设置分页对象
PageList pageList = new PageList<>(currentPage,pageSize,totalCount);
//分页查询数据
Integer beginIndex=(currentPage-1)*pageSize;
String sql="select * from t_images limit "+beginIndex+","+pageSize;
List data = this.jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Images.class));
pageList.setData(data);
return pageList;
}
//更新方法
@Override
public void update(Images images) {
String sql="update t_images set info=?,imagesIsEnable=? where id=?";
this.jdbcTemplate.update(sql,
images.getInfo(),
images.getImagesIsEnable(),
images.getId()
);
}
}
service层
package cn.xxx.service;
import java.util.List;
import cn.xxx.domain.Images;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
public interface IImagesService {
List queryAll();
void add(Images images);
void delete(Long id);
Images queryOne(Long id);
/**分页查询*/
PageList queryByPage(SqlCondition sqlCondition);
/**更新照片*/
void update(Images images);
}
package cn.xxx.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.xxx.dao.IImagesDao;
import cn.xxx.domain.Images;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
import cn.xxx.service.IImagesService;
@Service
public class ImagesServiceImpl implements IImagesService {
@Autowired
private IImagesDao imagesDaoImpl;
@Override
public List queryAll() {
return imagesDaoImpl.queryAll();
}
@Override
public void add(Images images) {
imagesDaoImpl.add(images);
}
@Override
public void delete(Long id) {
imagesDaoImpl.delete(id);
}
@Override
public Images queryOne(Long id) {
return imagesDaoImpl.queryOne(id);
}
@Override
public PageList queryByPage(SqlCondition sqlCondition) {
// TODO Auto-generated method stub
return imagesDaoImpl.queryByPage(sqlCondition);
}
@Override
public void update(Images images) {
// TODO Auto-generated method stub
imagesDaoImpl.update(images);
}
}
3.分页的实现
难点:分页的实现
需求:每次查询数据库降所有数据展示出来,阅读不便,而且数据量大,内存紧张
思路:采用真分页的方式,每次查询按照分页条件,进行分页查询展示,提供分页对象(包含当前页,总数据,每页展示的条数,可以得到下一页,上一页等),分页条件对象,注意分页返回的集合为泛型,谁使用就规定泛型。
分页对象:PageList
package cn.xxx.pagelist;
import java.io.Serializable;
import java.util.List;
public class PageList implements Serializable{
//分页查询的数据
private List data;
//第一页码
private Integer firstPage;
//前页码
private Integer prePage;
//下一页码
private Integer nextPage;
//最后页码
private Integer lastPage;
//总页数
private Integer totalPage;
//总数据量
private Integer totalCount;
//当前页码
private Integer currentPage;
//当前页面显示数据条数
private Integer pageSize;
public List getData() {
return data;
}
public void setData(List data) {
this.data = data;
}
public Integer getFirstPage() {
return firstPage;
}
public void setFirstPage(Integer firstPage) {
this.firstPage = firstPage;
}
public Integer getPrePage() {
return prePage;
}
public void setPrePage(Integer prePage) {
this.prePage = prePage;
}
public Integer getNextPage() {
return nextPage;
}
public void setNextPage(Integer nextPage) {
this.nextPage = nextPage;
}
public Integer getLastPage() {
return lastPage;
}
public void setLastPage(Integer lastPage) {
this.lastPage = lastPage;
}
public Integer getTotalPage() {
return totalPage;
}
public void setTotalPage(Integer totalPage) {
this.totalPage = totalPage;
}
public Integer getTotalCount() {
return totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}
public Integer getCurrentPage() {
return currentPage;
}
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
@Override
public String toString() {
return "PageList [data=" + data + ", firstPage=" + firstPage + ", prePage=" + prePage + ", nextPage=" + nextPage
+ ", lastPage=" + lastPage + ", totalPage=" + totalPage + ", totalCount=" + totalCount
+ ", currentPage=" + currentPage + ", pageSize=" + pageSize + "]";
}
public PageList() {
super();
// TODO Auto-generated constructor stub
}
/**提供一个有参的构造方法对字段赋值*/
public PageList(Integer currentPage,Integer pageSize,Integer totalCount ) {
//传入当前页码
this.currentPage=currentPage;
//传入每页页面展示的条数
this.pageSize=pageSize;
//传入总的数据量
this.totalCount=totalCount;
//计算第一页码
this.firstPage=1;
//计算最后页码
this.lastPage= totalCount%pageSize==0?totalCount/pageSize:totalCount/pageSize+1;
//计算总页码
this.totalPage=this.lastPage;
//计算前页码
this.prePage= currentPage==1?currentPage:currentPage-1;
//计算下页码
this.nextPage = currentPage
分页条件:SQLCondition
package cn.xxx.query;
import java.util.ArrayList;
import java.util.List;
/**
* @author peng
*定义分页的首页 每页展示的数据量
*/
/**
* @author peng
*
*/
public class SqlCondition {
//高级查询的title
private String title;
//高级查询positiontype
private Integer positiontype;
//首页
private Integer currentPage=1;
//每页数据量
private Integer pageSize=4;
//提供内置标识符 用来解决高级查询问题
private Boolean isEnableCache=false;
public Boolean getIsEnableCache() {
return isEnableCache;
}
public void setIsEnableCache(Boolean isEnableCache) {
this.isEnableCache = isEnableCache;
}
public SqlCondition(Integer currentPage, Integer pageSize) {
super();
this.currentPage = currentPage;
this.pageSize = pageSize;
}
@Override
public String toString() {
return "SqlCondition [title=" + title + ", positiontype=" + positiontype + ", currentPage=" + currentPage
+ ", pageSize=" + pageSize + "]";
}
public SqlCondition() {
super();
// TODO Auto-generated constructor stub
}
public Integer getCurrentPage() {
return currentPage;
}
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getPositiontype() {
return positiontype;
}
public void setPositiontype(Integer positiontype) {
this.positiontype = positiontype;
}
/**解决where还是and问题
* SQL方案一:
* where 1=1
*缺点:会把索引失效 查询效率低
*
*/
public String whereCondition1(){
String whereSql="where 1=1";
if(this.title!=null&&!"".equals(this.title)){
whereSql+=" and title like'%"+this.title+"%'";
}
if(this.positiontype!=null&&!"".equals(this.positiontype)){
whereSql+=" and positiontype="+this.positiontype;
}
return whereSql;
}
/**
* @return
* 方案二:
* 将数据装入list 进行遍历
* 第一个为where 其他为and
*/
public String whereCondition2(){
String whereSql="";
List whereConditionList = new ArrayList<>();
if(this.title!=null&&!"".equals(this.title)){
whereSql ="title like '%"+this.title+"%'";
whereConditionList.add(whereSql);
}
if(this.positiontype!=null&&!"".equals(this.positiontype)){
whereSql ="positiontype="+this.positiontype;
whereConditionList.add(whereSql);
}
if(whereConditionList!=null){
for (int i = 0; i < whereConditionList.size(); i++) {
if(i==0){
whereSql+=" where "+whereConditionList.get(i);
}else{
whereSql+=" and "+whereConditionList.get(i);
}
}
}
return whereSql;
}
/**
* @return
* 方案三:使用String方法replaceFirst("and", "where")
*/
public String whereCondition(){
String whereSql="";
if(this.title!=null&&!"".equals(this.title)){
whereSql+=" and title like '%"+this.title+"%'";
}
if(this.positiontype!=null&&!"".equals(this.positiontype)&&this.positiontype!=2){
whereSql+=" and positiontype="+this.positiontype;
}
return whereSql.replaceFirst("and", "where");
}
/**
* @return
* 采用一个标识符
*/
public String whereCondition3(){
String whereSql="";
Boolean isWhere=true;
if(this.title!=null&&!"".equals(this.title)){
if(isWhere){
whereSql+=" where ";
isWhere=false;
}else{
whereSql+=" and ";
}
whereSql+="like title='%"+this.title+"%'";
}
if(this.positiontype!=null&&!"".equals(this.positiontype)){
if(isWhere){
whereSql+=" where ";
isWhere=false;
}else{
whereSql+=" and ";
}
whereSql+="positiontype="+this.positiontype;
}
return whereSql;
}
}
4.页面静态化技术
难点;页面静态化技术
需求:每次前端在访问前台职位详情,都需要查询数据库,如果同时访问量大,那么数据库压力太大
思路:将前台职位详情的内容静态化处理(freemarker),提供模板,数据用freemarker,生成静态化页面(.html),存储在一起,当职位的详情发生改变时,将静态化内容,删除,并重新生成静态化页面(.html)
需要的jar:
join_us_details.ftl模板:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
物流校招
静态化
//增加静态化页面
public String addHtml(HttpServletRequest req,Jobs job) throws Exception{
//* 1.导入jar包freemarker.jar
//* 2.创建一个配置对象 1.传递一个版本
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
//* 3.设置模板加载路径
String realPath = req.getServletContext().getRealPath("/template");
File file=new File(realPath);
cfg.setDirectoryForTemplateLoading(file);
//* 4.设置一个模板编码
cfg.setDefaultEncoding("UTF-8");
//* 5.获取一个模板对象
Template template = cfg.getTemplate("join_us_details.ftl");
//* 6.获取一个数据 通过对象
//7.生成文件
String newName=UUID.randomUUID().toString()+".html";
PrintWriter pw = new PrintWriter(new File(file,newName));
template.process(job, pw);
pw.close();
//释放资源
System.gc();
return newName;
}
controller的调用:
package cn.xxx.web;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.sun.org.glassfish.gmbal.ParameterNames;
import cn.xxx.domain.Address;
import cn.xxx.domain.Jobs;
import cn.xxx.domain.User;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
import cn.xxx.service.IAddressService;
import cn.xxx.service.IJobsService;
import cn.xxx.service.impl.AddressServiceImpl;
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
* @author peng
*轮播管理后台
*/
@Controller
@RequestMapping("/jobs")
public class JobsController {
//注入图片服务对象调用底层方法
@Autowired
private IJobsService jobsServiceImpl;
@Autowired
private IAddressService addressServiceImpl;
//主页请求
@RequestMapping("/main")
public String mainJobs(){
return "forward:/WEB-INF/views/index.jsp";
}
//查询数据库 返回数据库的存储图片数据的集合 显示在主页上
/**分页查询*/
@RequestMapping("/list")
public String listJobs(Model model,SqlCondition sqlCondition){
//将高级查询禁用
sqlCondition.setTitle(null);
sqlCondition.setPositiontype(null);
PageList pageList = jobsServiceImpl.queryByPage(sqlCondition);
model.addAttribute("pageList", pageList);
//屏蔽视图处理器 跳转到查询主页
return "forward:/WEB-INF/jobs/jobs.jsp";
}
//-1----》新增标识
//编辑界面请求 根据id判断是进新增或者修改界面
@RequestMapping("/add")
public String addJobs(Model model){
List address = addressServiceImpl.queryAll();
model.addAttribute("address", address);
return "forward:/WEB-INF/jobs/jobs_add.jsp";
}
@RequestMapping("/edict/{id}")
public String edictJobs(Model model,@PathVariable("id") Long id,SqlCondition sqlCondition){
Jobs job = jobsServiceImpl.queryOne(id);
List address = addressServiceImpl.queryAll();
model.addAttribute("address", address);
model.addAttribute("job", job);
return "forward:/WEB-INF/jobs/jobs_edict.jsp";
}
//保存请求
@RequestMapping("/save")
public String saveJobs(HttpServletRequest req,Jobs job,SqlCondition sqlCondition) throws Exception{
if(!"".equals(job.getId())&&job.getId()!=null){
/**修改*/
String name=jobsServiceImpl.queryOne(Long.valueOf(job.getId()+"")).getHtmlurl();
String realPath=req.getServletContext().getRealPath("/template");
File file=new File(realPath,name);
file.delete();
//得到静态化界面名字
String htmlurl = this.addHtml(req,job);
//将值赋值给job对象
job.setHtmlurl(htmlurl);
//更新数据库
jobsServiceImpl.update(job);
}else{
System.out.println(11111);
/**新增*/
//得到静态化界面名字
String htmlurl = this.addHtml(req,job);
//将值赋值给job对象
job.setHtmlurl(htmlurl);
//添加到数据库
jobsServiceImpl.add(job);
}
return "forward:/jobs/list";
}
//增加静态化页面
public String addHtml(HttpServletRequest req,Jobs job) throws Exception{
//* 1.导入jar包freemarker.jar
//* 2.创建一个配置对象 1.传递一个版本
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
//* 3.设置模板加载路径
String realPath = req.getServletContext().getRealPath("/template");
File file=new File(realPath);
cfg.setDirectoryForTemplateLoading(file);
//* 4.设置一个模板编码
cfg.setDefaultEncoding("UTF-8");
//* 5.获取一个模板对象
Template template = cfg.getTemplate("join_us_details.ftl");
//* 6.获取一个数据 通过对象
//7.生成文件
String newName=UUID.randomUUID().toString()+".html";
PrintWriter pw = new PrintWriter(new File(file,newName));
template.process(job, pw);
pw.close();
//释放资源
System.gc();
return newName;
}
//删除请求
@RequestMapping("/delete/{id}")
public String deleteJobs(@PathVariable("id")Long id,HttpServletRequest req){
Jobs job=jobsServiceImpl.queryOne(id);
String name=job.getHtmlurl();
String realPath=req.getServletContext().getRealPath("/template");
File file=new File(realPath,name);
file.delete();
jobsServiceImpl.delete(id);
return "forward:/jobs/list";
}
}
5.缓存技术
难点:缓存的应用
需求:解决每次查询都需要重复去数据库查询效率低效问题
思路:使用缓存存储数据,先查询缓存中是否有数据,有用缓存的,没有查询数据库,而将新查询的数据保存到缓存中,注意删除,新增,修改都需要通过标识符重新查询的数据库
带来的问题:高级查询和普通查询共用一个查询service方法,那么高级查询之前应该将标识符改正为从数据库查询
使用的jar包:
缓存工具类
package cn.itsource.myutils;
import java.util.List;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
/**
* @author peng
*缓存工具
*/
public class CacheUtils {
/**
* @param cacheManager
* @param key
* @param object
* @param cacheName
* 存储方法
*/
public static void setCacheData(CacheManager cacheManager,String key,Object object,String cacheName){
//拿到缓存管理对象
cacheManager = CacheManager.create();
//准备数据
//拿到缓存对象 存储数据
Cache cache = cacheManager.getCache(cacheName);
Element element=new Element(key, object);
cache.put(element);
}
/**
* @param cacheManager
* @param key
* @param cacheName
* @return
* 取出方法
*/
public static Object getCacheData(CacheManager cacheManager,String key,String cacheName){
Object elementValue=null;
try {
Cache cache = cacheManager.getCache(cacheName);
Element element = cache.get(key);
elementValue = element.getObjectValue();
} catch (Exception e) {
// TODO: handle exception
return elementValue;
}
return elementValue;
}
}
package cn.xxx.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.xxx.dao.IJobsDao;
import cn.xxx.domain.Jobs;
import cn.xxx.myutils.CacheUtils;
import cn.xxx.pagelist.PageList;
import cn.xxx.query.SqlCondition;
import cn.xxx.service.IJobsService;
import net.sf.ehcache.CacheManager;
@Service
public class JobsServiceImpl implements IJobsService {
/**用来判断是否需要新增缓存 默认为flase不需要缓存
* 新增 删除 修改 需要更新缓存
*
* */
private Boolean isEnableCache=false;
@Autowired
private IJobsDao jobsDaoImpl;
@Override
public List queryAll() {
return jobsDaoImpl.queryAll();
}
@Override
public void add(Jobs Jobs) {
jobsDaoImpl.add(Jobs);
isEnableCache=true;
}
@Override
public void delete(Long id) {
jobsDaoImpl.delete(id);
isEnableCache=true;
}
@Override
public Jobs queryOne(Long id) {
return jobsDaoImpl.queryOne(id);
}
@Override
public PageList queryByPage(SqlCondition sqlCondition) {
PageList queryByPage = null;
//创建缓存管理者
CacheManager cacheManager = CacheManager.create();
//每次不同的存入key
String key="key_"+sqlCondition.getCurrentPage();
//缓存名称
String cacheName="jobsCache";
if(sqlCondition.getTitle()!=null&&!"".equals(sqlCondition.getTitle())){
/**
* 使用高级查询 将缓存重新清理
*/
sqlCondition.setIsEnableCache(true);
}
if(sqlCondition.getPositiontype()!=null&&!"".equals(sqlCondition.getPositiontype())&&sqlCondition.getPositiontype()!=2){
sqlCondition.setIsEnableCache(true);
}
//静态化操作
/**取出缓存*/
queryByPage = (PageList) CacheUtils.getCacheData(cacheManager, key, cacheName);
/**如果未取出数据,进行查询存储数据到缓存*/
if(queryByPage==null||isEnableCache||sqlCondition.getIsEnableCache()){
//如果标识符为ture表名内容已修改需要更新缓存
if(isEnableCache){
//删除原来缓存数据
cacheManager.getCache(cacheName).removeAll();
}
queryByPage = jobsDaoImpl.queryByPage(sqlCondition);
CacheUtils.setCacheData(cacheManager, key, queryByPage, cacheName);
isEnableCache=false;
}
return queryByPage;
}
@Override
public void update( Jobs job) {
// TODO Auto-generated method stub
jobsDaoImpl.update(job);
isEnableCache=true;
}
@Override
public List queryByCondition(SqlCondition sqlCondition) {
// TODO Auto-generated method stub
return jobsDaoImpl.queryByCondition(sqlCondition);
}
}
6.高级查询
难点:高级查询的实现
需求:需要模糊查询职位的名称和是否全职
思路:通过多条件SQL语句进行后台查询,将SQL条件封装在分页条件中,关键处理第一个条件需要语句开始为where 而其他为and,使用String替换第一个的方法。
问题:出现缓存与高级查询不兼容问题
package cn.itsource.myutils;
import java.util.List;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
/**
* @author peng
*缓存工具
*/
public class CacheUtils {
/**
* @param cacheManager
* @param key
* @param object
* @param cacheName
* 存储方法
*/
public static void setCacheData(CacheManager cacheManager,String key,Object object,String cacheName){
//拿到缓存管理对象
cacheManager = CacheManager.create();
//准备数据
//拿到缓存对象 存储数据
Cache cache = cacheManager.getCache(cacheName);
Element element=new Element(key, object);
cache.put(element);
}
/**
* @param cacheManager
* @param key
* @param cacheName
* @return
* 取出方法
*/
public static Object getCacheData(CacheManager cacheManager,String key,String cacheName){
Object elementValue=null;
try {
Cache cache = cacheManager.getCache(cacheName);
Element element = cache.get(key);
elementValue = element.getObjectValue();
} catch (Exception e) {
// TODO: handle exception
return elementValue;
}
return elementValue;
}
}
7.邮箱激活技术
难点:邮箱的激活
需求:用户注册后,需要激活后才能使用
思路:注册后,自动根据用户提供的邮箱地址,发送到邮箱中,点击传来UUID,将用户是否可用的字段设置为可用。
package cn.itsource.service.impl;
import java.util.Properties;
import java.util.UUID;
import javax.mail.Message;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.itsource.dao.IUserDao;
import cn.itsource.domain.User;
import cn.itsource.service.IUserService;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao UserDaoImpl;
@Override
public void add(User user) throws Exception {
//生成一个uuid
user.setUUID((UUID.randomUUID().toString()));
UserDaoImpl.add(user);
//发送邮件
Properties prop = new Properties();
prop.setProperty("mail.host", "127.0.0.1");
prop.setProperty("mail.transport.protocol", "smtp");
prop.setProperty("mail.smtp.auth", "true");
// 使用JavaMail发送邮件的5个步骤
// 1、创建session
Session session = Session.getInstance(prop);
// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
session.setDebug(true);
// 2、通过session得到transport对象
Transport ts = session.getTransport();
// 3、使用邮箱的用户名和密码连上邮件服务器,发送邮件时,发件人需要提交邮箱的用户名和密码给smtp服务器,用户名和密码都通过验证之后才能够正常发送邮件给收件人。
ts.connect("127.0.0.1", "a", "a");
// 4、创建邮件
Message message = createSimpleMail(session,user.getUUID(),user);
// 5、发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}
public MimeMessage createSimpleMail(Session session,String uuid,User user) throws Exception {
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人
message.setFrom(new InternetAddress("[email protected]"));
// 指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发
message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
// 邮件的标题
message.setSubject("登录激活");
// 邮件的文本内容
message.setContent("亲爱的"+user.getUsername()+"!验证用户注册", "text/html;charset=UTF-8");
// 返回创建好的邮件对象
return message;
}
@Override
public User queryOneUser(User user) {
return UserDaoImpl.queryOneUser(user);
}
@Override
public void updateUser(String UUID) {
// TODO Auto-generated method stub
UserDaoImpl.updateUser(UUID);
}
}
8.Spring拦截
拦截无登录的后台访问请求
需求:用户需要有效的登录才能访问到后台管理
思路:使用Spring自带的拦截器,配置需要拦截的路径,和放行的路径,在拦截方法中,判断是否存在成功登录的session才放行
拦截器的配置
拦截器:
package cn.itsource.domain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("DispatcherServlet完结之后调用");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("处理完请求之后");
}
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object obj2) throws Exception {
HttpSession session = req.getSession();
Object obj = session.getAttribute("user");
if (obj==null) {
System.out.println("没有登录");
//登录放行
req.getRequestDispatcher("/login.jsp").forward(req, resp);
return false; //执行之后,不用放行
}
return true;
}
}
登录controller
package cn.itsource.web;
import javax.servlet.http.HttpServletRequest;
import javax.swing.plaf.synth.SynthSpinnerUI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.itsource.domain.User;
import cn.itsource.service.IUserService;
@Controller
public class LoginController {
@Autowired
private IUserService userService;
@RequestMapping("/login")
public String login(HttpServletRequest req,User user){
String randomcode = req.getParameter("random");
/**校验验证码*/
if(randomcode==null||"".equals(randomcode)){
req.setAttribute("error", "亲,验证码不能为空");
return "forward:/login.jsp";
}
if(!randomcode.equals(req.getSession().getAttribute("randomcode_IN_SESSION"))){
req.setAttribute("error", "亲,验证码输入错误");
return "forward:/login.jsp";
}
System.out.println(user);
//先判断是否有此用户 无该用户返回登录页面
//查询存在的用户在数据库的对象
User userForLogin = userService.queryOneUser(user);
if(userForLogin!=null&&userForLogin.getUUID()!=null&&!"".equals(userForLogin.getUUID())){
//判断该用户有权限进行登录功能
if(userForLogin.getIsEnable()){
req.getSession().setAttribute("user", userForLogin);
return "forward:/main/index";
}
req.setAttribute("error", "亲,你的用户还未激活,请尽快进行激活");
return "forward:/login.jsp";
}
req.setAttribute("error", "亲,你的用户未注册或密码错误");
return "forward:/login.jsp";
}
//注册方法,发送邮件
@RequestMapping("/signup")
public String signup(HttpServletRequest req,User user) throws Exception{
userService.add(user);
req.setAttribute("error", "亲,请尽快完成邮件注册,请先进行注册");
return "forward:/login.jsp";
}
//邮件发送后 点击完成注册方法
@RequestMapping("/update")
public String update(HttpServletRequest req,User user){
System.out.println(user.getUUID());
userService.updateUser(user.getUUID());
return "forward:/login.jsp";
}
}
9.富文本编辑器
富文本编辑器的使用
需求:在添加说明时,需要更多的组件完成文本的输入
思路:使用富文本编辑器
package cn.itsource.web;
import javax.servlet.http.HttpServletRequest;
import javax.swing.plaf.synth.SynthSpinnerUI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.itsource.domain.User;
import cn.itsource.service.IUserService;
@Controller
public class LoginController {
@Autowired
private IUserService userService;
@RequestMapping("/login")
public String login(HttpServletRequest req,User user){
String randomcode = req.getParameter("random");
/**校验验证码*/
if(randomcode==null||"".equals(randomcode)){
req.setAttribute("error", "亲,验证码不能为空");
return "forward:/login.jsp";
}
if(!randomcode.equals(req.getSession().getAttribute("randomcode_IN_SESSION"))){
req.setAttribute("error", "亲,验证码输入错误");
return "forward:/login.jsp";
}
System.out.println(user);
//先判断是否有此用户 无该用户返回登录页面
//查询存在的用户在数据库的对象
User userForLogin = userService.queryOneUser(user);
if(userForLogin!=null&&userForLogin.getUUID()!=null&&!"".equals(userForLogin.getUUID())){
//判断该用户有权限进行登录功能
if(userForLogin.getIsEnable()){
req.getSession().setAttribute("user", userForLogin);
return "forward:/main/index";
}
req.setAttribute("error", "亲,你的用户还未激活,请尽快进行激活");
return "forward:/login.jsp";
}
req.setAttribute("error", "亲,你的用户未注册或密码错误");
return "forward:/login.jsp";
}
//注册方法,发送邮件
@RequestMapping("/signup")
public String signup(HttpServletRequest req,User user) throws Exception{
userService.add(user);
req.setAttribute("error", "亲,请尽快完成邮件注册,请先进行注册");
return "forward:/login.jsp";
}
//邮件发送后 点击完成注册方法
@RequestMapping("/update")
public String update(HttpServletRequest req,User user){
System.out.println(user.getUUID());
userService.updateUser(user.getUUID());
return "forward:/login.jsp";
}
}
本项目多个地方值得优化,如登录和注册,地址的查询都可以换方式更简单的实现,主要锻炼了Spring框架的使用,和前后端交互的认识