Jsp+Servlet+JDBC新闻发布系统2.0

很久之前写了这样一篇博客,就很久没有更新博客了,后面陆陆续续有看官在下面评论,询问一些问题。由于之前写的实在是时代久远,索性直接重构了一遍,重构过后的系统界面如下:

开发环境:

  • windows
  • eclipse
  • mysql

体验区http://www.nicecoder.cn

操作区http://www.nicecoder.cn/newspublishsystem/login.jsp


首页

首页还沿用之前的样式,稍作调整。提供按条件查询新闻,可以根据新闻类型关键字类型+关键字进行检索。

  • 加载方式采用了无限下拉分页加载,判断滚动条到了底部:$(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标签。
  1.    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>    

  2.    创建类,创建方法
    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;
    	}
    	
    }
  3.    调用方式,jsp里面调用如下
    <%@ taglib uri="/WEB-INF/mytag.tld" prefix="myTag" %> //顶部添加
  4. <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一样使用注解。
  1. @WebServlet(name="imageUpload", urlPatterns="/imageUpload") 替代web.xml配置方式。
  2. @MultipartConfig  提供HttpServletRequest对文件上传的支持。通过Part p = req.getPart("name");name是input标签的name,如果name是不确定的,那么久用下面这种获取集合的方式获取到Part集合,再遍历之。通过下列一系列操作就可以把本地文件、图片上传到服务器。然后就可以被页面引用啦。
  3. 图片压缩是必要的,如果上传的图片过大,不仅占网速,占空间,在显示的时候也会出现问题,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”获取。这样做是防止乱搞,非诚勿扰。同时也是测试下公众号。个体未认证公众号没啥接口可以耍,哎~当然系统也可能有bug,可以绕过登录-_-。

  • 禁止访问页面,登录密码错误或者session过期都会跳到此页面。

                


数据库设计

系统共用了四张表,news<新闻表>,newsclass<新闻类别>,discuss<评论表>,agree<点赞表>

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 类型名

猜你喜欢

转载自blog.csdn.net/l4642247/article/details/80267411