很久之前写了这样一篇博客,就很久没有更新博客了,后面陆陆续续有朋友在下面评论,询问一些问题。由于之前写的实在是时代久远,索性直接重构了一遍,重构过后的系统界面如下:
开发环境:
- windows
- eclipse
- mysql
白嫖地址
链接: https://pan.baidu.com/s/1-Fojg6p36GjiiWZSvLr-AA 提取码: n4em
【首页】
首页还沿用之前的样式,稍作调整。提供按条件查询新闻,可以根据新闻类型、关键字、类型+关键字进行检索。
- 加载方式采用了无限下拉分页加载,判断滚动条到了底部:$(window).scrollTop() == $(document).height() – $(window).height();
$(function(){
var flag = 0;
$(window).scroll(function(){
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
var pageCount = $("input[name='pageCount']").val();
var pageNo = $("input[name='pageNo']").val();
var keyWord = $("input[name='keyWord']").val();
var type = $("input[name='type']").val();
if(pageNo < pageCount){
$.ajax({
url:"coreServlet?bizCode=7",
dataType:"json",
data:{'keyword':keyWord, 'type':type, 'pageNo':parseInt(pageNo)+1},
success:function(data){
var html = "";
$.each(data.newsList, function(i,val){
html += '<div class="new"> ';
html += ' <div class="content row">';
html += ' <div class="imgdiv">';
html += ' <a href="coreServlet?bizCode=4&id='+val.id+'"><img src="'+val.img+'"/></a>';
html += ' </div>';
html += ' <div class="text">';
html += ' <a href="coreServlet?bizCode=4&id='+val.id+'"><h4>"'+val.title+'</h4></a>';
html += ' <p class="p1">"'+val.pudate+'-"'+val.type+'-"'+val.author+'-阅"'+val.click+'</p>';
html += ' <p class="p2">"'+val.content+'</p>';
html += ' </div>';
html += ' </div>';
html += '</div> ';
});
$(".new").last().after(html);
$("input[name='pageNo']").val(parseInt(pageNo) + 1);
}
});
}else if(pageNo == pageCount && flag == 0){
flag ++;
var html = '<p style="text-align:center; color:#FF8C69; font-size:14px; margin-top:10px; margin-bottom:10px;">-没有更多了-</p>';
$(".new").last().after(html);
}
}
});
});
- 时间格式化:采用自定义jstl标签。
- WEB-INF下面创建mytag.tld
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>myTag</short-name> <function> <description>date change</description><!-- 对这个EL方法的描述 --> <name>formatDate</name><!-- 调用EL方法的名称 --> <function-class>cn.nicecoder.util.UFunction</function-class> <function-signature> java.lang.String formatDate(java.lang.String) </function-signature> <example>${myTag:formatDate(str)}</example><!-- 例如 --> </function> </taglib>
- 创建类,创建方法
public class UFunction { /** * 转换格式"年-月-日" * @param dateTime * @return */ public static String formatDate(String dateTime){ if(StringUtil.isNotEmpty(dateTime)){ return dateTime.substring(0,4) + "-" +dateTime.substring(4,6) + "-" + dateTime.substring(6,8); } return dateTime; } }
- 调用方式,jsp里面调用如下
<%@ taglib uri="/WEB-INF/mytag.tld" prefix="myTag" %> //顶部添加
-
<p class="p1">${myTag:formatDate(news.pudate)} - <span style="color: #20B2AA;">${news.type}</span> - ${news.author} - 阅${news.click}</p>
【详情页】
详情页和下面的管理员页面都采用了我最近发现的一个好用的UI框架layui,这个框架有自己的社区,而且持续更新中,感兴趣的可以百度layui。抛弃了在我看来只适合做后端的bootstrap。提供了发表评论和点赞评论功能。评论评论和点赞文章功能也有预留,type传值不同罢了,但是ui要稍作修改,暂时还没想好,后续可能会加上。评论的头像显示,再加入用户表之后也可以完善进去。
- layui富文本编辑器,功能不是很强,但是我更看中它的简洁和外观,鹅且持续更新中,用法见官网。
- 锚点定位,滑下来再滑上去手会很痛。使用起来很简单。
<a name="mao"></a>//点击下面的a标签会跳转到这里
<a href="#mao" ><i class="layui-icon layui-icon-face-smile"></i></a>//图中的top箭头
- ajax异步提交评论
function discuss(type, id){ $("#dis-btn").attr("disabled","true"); var content = layedit.getContent(index); $.ajax({ dataType:'json', data :{'content':content, 'type':type, 'id':id}, url :"coreServlet?bizCode=5", async : true, success :function(data){ location.href = "coreServlet?bizCode=4&id="+ id; } }); }
- 获取请求的IP,得到IP的地区信息,这两个就从别的地方借来用用,这里记录一下,有点长但是很好用。
public class IPUtil { public static String getIpAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } }
public class AddressUtil{ /** * * @param content * 请求的参数 格式为:name=xxx&pwd=xxx * @param encoding * 服务器端请求编码。如GBK,UTF-8等 * @return * @throws UnsupportedEncodingException */ public static String getAddresses(String content, String encodingString)throws UnsupportedEncodingException { // 这里调用pconline的接口 String urlStr = "http://ip.taobao.com/service/getIpInfo.php"; // 从http://whois.pconline.com.cn取得IP所在的省市区信息 String returnStr = getResult(urlStr, content, encodingString); if (returnStr != null) { // 处理返回的省市区信息 String[] temp = returnStr.split(","); if(temp.length<3){ return "0";//无效IP,局域网测试 } String region = (temp[5].split(":"))[1].replaceAll("\"", ""); region = decodeUnicode(region);// 省份 String country = ""; String area = ""; // String region = ""; String city = ""; String county = ""; String isp = ""; for (int i = 0; i < temp.length; i++) { switch (i) { case 1: country = (temp[i].split(":"))[2].replaceAll("\"", ""); country = decodeUnicode(country);// 国家 break; case 3: area = (temp[i].split(":"))[1].replaceAll("\"", ""); area = decodeUnicode(area);// 地区 break; case 5: region = (temp[i].split(":"))[1].replaceAll("\"", ""); region = decodeUnicode(region);// 省份 break; case 7: city = (temp[i].split(":"))[1].replaceAll("\"", ""); city = decodeUnicode(city);// 市区 break; case 9: county = (temp[i].split(":"))[1].replaceAll("\"", ""); county = decodeUnicode(county);// 地区 break; case 11: isp = (temp[i].split(":"))[1].replaceAll("\"", ""); isp = decodeUnicode(isp); // ISP公司 break; } } return region; } return null; } /** * @param urlStr * 请求的地址 * @param content * 请求的参数 格式为:name=xxx&pwd=xxx * @param encoding * 服务器端请求编码。如GBK,UTF-8等 * @return */ private static String getResult(String urlStr, String content, String encoding) { URL url = null; HttpURLConnection connection = null; try { url = new URL(urlStr); connection = (HttpURLConnection) url.openConnection();// 新建连接实例 connection.setConnectTimeout(2000);// 设置连接超时时间,单位毫秒 connection.setReadTimeout(2000);// 设置读取数据超时时间,单位毫秒 connection.setDoOutput(true);// 是否打开输出流 true|false connection.setDoInput(true);// 是否打开输入流true|false connection.setRequestMethod("POST");// 提交方法POST|GET connection.setUseCaches(false);// 是否缓存true|false connection.connect();// 打开连接端口 DataOutputStream out = new DataOutputStream(connection.getOutputStream());// 打开输出流往对端服务器写数据 out.writeBytes(content);// 写数据,也就是提交你的表单 name=xxx&pwd=xxx out.flush();// 刷新 out.close();// 关闭输出流 BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding));// 往对端写完数据对端服务器返回数据 // ,以BufferedReader流来读取 StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = reader.readLine()) != null) { buffer.append(line); } reader.close(); return buffer.toString(); } catch (IOException e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect();// 关闭连接 } } return null; } /** * unicode 转换成 中文 * * @author fanhui 2007-3-15 * @param theString * @return */ public static String decodeUnicode(String theString) { char aChar; int len = theString.length(); StringBuffer outBuffer = new StringBuffer(len); for (int x = 0; x < len;) { aChar = theString.charAt(x++); if (aChar == '\\') { aChar = theString.charAt(x++); if (aChar == 'u') { int value = 0; for (int i = 0; i < 4; i++) { aChar = theString.charAt(x++); switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: throw new IllegalArgumentException( "Malformed encoding."); } } outBuffer.append((char) value); } else { if (aChar == 't') { aChar = '\t'; } else if (aChar == 'r') { aChar = '\r'; } else if (aChar == 'n') { aChar = '\n'; } else if (aChar == 'f') { aChar = '\f'; } outBuffer.append(aChar); } } else { outBuffer.append(aChar); } } return outBuffer.toString(); } // 测试 public static void main(String[] args) { AddressUtil addressUtils = new AddressUtil(); String ip = "0:0:0:0:0:0:0:1"; String address = ""; try { address = addressUtils.getAddresses("ip=" + ip, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(address); } }
【管理员】
管理员页面依然采用的layui,实现了对新闻的发布,编辑,详情,删除。
- 点击箭头分页和首页采用的同一个js方法,传的参数不同。
- 类型转义可做成数据字典,通过自定义jstl标签进行转义显示。
- 上传图片,点击上传图片按钮和文章中插入图片采用同一个接口。采用的servlet3.0。好处就是写servlet不用配置web.xml,可以像springMVC一样使用注解。
- @WebServlet(name=”imageUpload”, urlPatterns=”/imageUpload”) 替代web.xml配置方式。
- @MultipartConfig 提供HttpServletRequest对文件上传的支持。通过Part p = req.getPart(“name”);name是input标签的name,如果name是不确定的,那么久用下面这种获取集合的方式获取到Part集合,再遍历之。通过下列一系列操作就可以把本地文件、图片上传到服务器。然后就可以被页面引用啦。
- 图片压缩是必要的,如果上传的图片过大,不仅占网速,占空间,在显示的时候也会出现问题,img会撑破div跑到外面去。后端处理方式通过Thumbnails这个jar包提供一些方法进行压缩,可以判断文件大小,也可以判断宽高,我采用的是宽高。同款jar包下载就在我的资源。
前端处理方式(发布新闻的时候,我是通过复制别的地方的新闻,图片自然就是引用的网上的地址,没有经过后台上传。没 有被压缩,显示会出问题。解决方法:img {max-width:762px;overflow:hidden;})
package cn.nicecoder.servlet;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import net.coobird.thumbnailator.Thumbnails;
import net.sf.json.JSONObject;
/**
* 上传文件servlet
*-------------------------------
* @author longtian
* @date 2018年4月23日下午11:09:00
* @description nicecoder.cn
*-------------------------------
*/
@WebServlet(name="imageUpload", urlPatterns="/imageUpload")
@MultipartConfig
public class UploadImageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
Collection<Part> parts = req.getParts();
JSONObject result = new JSONObject();
//Part p = req.getPart("name");
for (Part part : parts) {
String disposition = part.getHeader("content-disposition");
System.out.println("文件描述:" + disposition);
//文件名,文件类型,文件大小
String fileName = disposition.substring(disposition.lastIndexOf("=")+2, disposition.length()-1);
String fileType = part.getContentType();
long fileSize = part.getSize();
System.out.println("fileName: " + fileName);
System.out.println("fileType: " + fileType);
System.out.println("fileSize: " + fileSize);
//1.服务器保存文件路径
String uploadPath = this.getServletConfig().getServletContext().getRealPath("/");
//2.文件夹按日期分类
String folder = new SimpleDateFormat("yyyyMMdd").format(new Date());
//3.拼接文件名
if(!new File(uploadPath + File.separator + folder).exists()) {
new File(uploadPath + File.separator + folder).mkdirs();
}
//重命名并写入文件
fileName = new SimpleDateFormat("yyyyMMdd_HHmmSS").format(new Date()) + fileName.subSequence(fileName.indexOf("."), fileName.length());
part.write(uploadPath + folder + File.separator + fileName);
//返回存储地址
String src = uploadPath + folder + File.separator + fileName;
BufferedImage bufferedImage = ImageIO.read(new File(src));
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
//图片过大的压缩一下
if(width > 762){
double scale = new BigDecimal((float)762/width).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
Thumbnails.of(src).size(762,(int) (height * scale)).keepAspectRatio(false).toFile(src);
}
result.put("code", 0);
result.put("msg", "ok");
JSONObject subObject = new JSONObject();
subObject.put("src", folder + File.separator + fileName );
subObject.put("title", fileName);
result.put("data", subObject);
/*适应layui,所以返回如下格式{
"code": 0 //0表示成功,其它失败
,"msg": "" //提示信息 //一般上传失败后返回
,"data": {
"src": "图片路径"
,"title": "图片名称" //可选
}
}*/
}
PrintWriter wp = resp.getWriter();
wp.write(result.toString());
wp.close();
}
}
【其他页面】
管理员登录页面和权限页面,后期可能会加404页面,这里就一笔带过。
- 管理员登录,管理员界面通关口令通过微信公众号【在相思树下】,回复“1”获取。这样做是防止乱搞,非诚勿扰。公众号也可能会突然分享一波源码的链接,平时不会胡乱推送,可以放心关注啦~。
- 禁止访问页面,登录密码错误或者session过期都会跳到此页面。
【数据库设计】
系统共用了五张表,news<新闻表>,newsclass<新闻类别>,discuss<评论表>,agree<点赞表>,user<用户表>
news表 | |||
名 | 类型 | 长度 | 备注 |
id | int | 10 | 序号 |
img | varchar | 100 | 封面 |
title | varchar | 50 | 标题 |
content | blob | 0 | 内容 |
type | varchar | 10 | 类型 |
author | varchar | 50 | 作者 |
pudate | varchar | 50 | 修改时间 |
click | varchar | 20 | 点击量 |
discuss表 | |||
名 | 类型 | 长度 | 备注 |
id | int | 10 | 序号 |
type | varchar | 10 | 类型 |
discussid | varchar | 10 | 评论内容编号 |
content | blob | 0 | 内容 |
userid | varchar | 50 | 作者 |
pudate | varchar | 50 | 修改时间 |
agree | varchar | 20 | 点赞量 |
agree表 | |||
名 | 类型 | 长度 | 备注 |
id | int | 10 | 序号 |
type | varchar | 10 | 类型 |
agreeid | varchar | 10 | 点赞内容编号 |
userid | varchar | 50 | 作者 |
pudate | varchar | 50 | 修改时间 |
newsclass表 | |||
名 | 类型 | 长度 | 备注 |
id | int | 11 | 序号 |
clsname | varchar | 20 | 类型名 |
user表 | |||
名 | 类型 | 长度 | 备注 |
id | int | 11 | 序号 |
image | varchar | 255 | 头像 |
name | varchar | 255 | 昵称 |
ip | varchar | 20 | 评论人ip |
胡乱写了一堆,可能有的朋友对该项目的源码已经产生了一丢丢的兴趣。那么下面将放出源码的获取方式。虽然是个小项目,但是也投入了一定的精力,所以肯定不能无偿获取哈,希望能够理解。同时项目中仍有许多不足之处,也请多多批评指正。
方式一:CSDN资源下载链接,此乃土豪获取方式,仅需挥洒区区5个积分,便能立马将文中所述同款源码一波带走,简单而又粗暴。
方式二:通过公众号【在相思树下】,回复“签到”二字连续签到3天,亦可获得同款源码下载链接。而且后期有一些小项目的源码也能第一时间获取得到。敬请关注。有的朋友在公众号上私信我,说很着急,想立即获得源码的,请用方式一。说什么也没用,不听~不听~
公众号的回复是机器人回复,我不一定能够实时看见。BUG肯定是有的,有什么问题先自行研究,如果实在不行就在下面留言,或者私信,有时候回复较慢,请见谅。
2020-8-21 公众号故障中。。。
附:链接: https://pan.baidu.com/s/149VZ2ORNLk9eE4WP2ZxGHA 提取码: 39dt 包含表结构和数据。
白嫖地址
链接: https://pan.baidu.com/s/1-Fojg6p36GjiiWZSvLr-AA 提取码: n4em
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/37882.html