旅游网小项目总结

六天小项目使用技术:
  1. 旅游网前台用户界面,纯异步开发
    使用技术:HTML+jQuery+Servlet+JdbcTemplate
  2. 旅游网后台管理,纯同步开发
    使用技术:JSP+JSTL+EL+Servlet+JdbcTemplate
    提供工具类MD5加密,验证码,已及前端页面,大部分只通过三层架构写后端代码:
MD5加密:
import java.math.BigInteger;
import java.security.MessageDigest;

public class Md5Utils {

    /**
     * 对给定的字符使用md5进行加密,返回加密以后的字符串
     * 
     * @param origin
     * @return
     */
    public static String getMd5(String origin) {
        // 1) 使用静态方法,创建MessageDigest对象
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 2) 将字符串使用utf-8进行编码,得到字节数组
            byte[] input = origin.getBytes("utf-8");
            // 3) 使用digest(input)对字节数组进行md5的哈希计算,得到加密以后的字节数组,长度是16个字节。
            byte[] num = md.digest(input);
            // 4) 使用类BigInteger(1, 加密后的字节数组),将这个二进制数组转成无符号的大整数
            // 1 正数, -1表示负数
            BigInteger big = new BigInteger(1, num);
            // 5) 将这个大整数转成16进制字符串,参数为多少进制
            return big.toString(16);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        System.out.println(getMd5("123"));
        System.out.println(getMd5("abc"));
    }
}
验证码
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

/**
 * 创建一个验证码图片
 */
@WebServlet("/code")
public class PicCodeServlet extends HttpServlet {
    private Random ran = new Random();      //随机类

    //1) 写一个方法随机获取颜色
    private Color getColor() {
        //红,绿,蓝取值0-255,随机生成 0-255之间数
        int r = ran.nextInt(256);
        int g = ran.nextInt(256);
        int b = ran.nextInt(256);
        return new Color(r, g, b);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //2) 创建缓存图片:指定宽
        int width = 90, height = 30;
        //参数3:图片的类型,使用RGB类型
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //3) 获取画笔对象
        Graphics graphics = image.getGraphics();
        //4) 设置画笔颜色,并且填充矩形区域
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);
        //创建一个StringBuider对象
        StringBuilder sb = new StringBuilder();
        //5) 从字符数组中随机得到字符
        char[] arr = {'A', 'B', 'C', 'D', 'N', 'E', 'W', 'b', 'o', 'y', '1', '2', '3', '4', '5', '6'};
        for (int i = 0; i < 4; i++) {
            //随机从0到长度之间去取索引
            int index = ran.nextInt(arr.length);
            //得到1个字符
            char c = arr[index];
            sb.append(c);
            //6) 设置字体,大小为18,设置字的颜色随机
            graphics.setFont(new Font(Font.DIALOG, Font.BOLD + Font.ITALIC, 18));
            graphics.setColor(getColor());
            //7) 将每个字符画到图片,位置:5+(i*20), 20
            //将字符转成字符串
            graphics.drawString(String.valueOf(c), 5 + (i * 20), 20);
        }
        System.out.println("生成的验证码:" + sb);
        //得到验证码,将生成的字符串放到会话域中
        request.getSession().setAttribute("vcode", sb.toString());
        //8) 画干扰线8条线,线的位置是随机的,x范围在width之中,y的范围在height之中。
        for (int i = 0; i < 8; i++) {
            graphics.setColor(getColor());
            int x1 = ran.nextInt(width);
            int y1 = ran.nextInt(height);
            int x2 = ran.nextInt(width);
            int y2 = ran.nextInt(height);
            graphics.drawLine(x1, y1, x2, y2);
        }
        //9) 将缓存的图片输出到响应输出流中
        //参数1:要输出的缓存图片,参数2:格式,参数3:输出到哪个流中
        ImageIO.write(image, "jpeg", response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 处理所有post方法提交的汉字乱码的问题
 */
@WebFilter("/*")
public class EncodeFilter implements Filter {
    public void destroy() {
    }

    //执行过滤的功能
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //转成子接口
        HttpServletRequest request = (HttpServletRequest) req;
        //如果是post请求,对汉字进行编码
        if ("POST".equals(request.getMethod())) {
            request.setCharacterEncoding("utf-8");
        }
        //放行
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

面向接口编程:

模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。
可扩展性和可维护性更强

  1. 隐藏实现:Web层只调用service接口,service层只调用Dao接口,上一层只调用下一层接口,不需要知道具体实现类,从而隐藏了实现。
  2. 易扩展:系统功能升级扩展,我们知道程序设计的原则是对修改是关闭,对新增是开放。面向接口编程扩展功能只需要创建新实现类,重写接口方法进行升级扩展就可以了,达到了可以不修改源程序代码的基础上达到扩展的目的。

在linux上发布项目:

  1. 先在idea中对旅游项目打包,使用maven中的package命令,得到war文件,文件大小76M。改名为travel.war。注:会执行所有的test类,如果有测试不能通过,则打包失败,如果有乱码忽略。

  2. 上传war文件到/usr/local/apache-tomcat-8.5.27/webapp目录下

  3. 启动tomcat: 在bin/startup.sh

  4. 启动redis: 在redis/bin下 输入命令 ./redis-server redis.conf

  5. 打开浏览器浏览网站:[http://ip....:8080/travel/]

Nginx服务器:

作用:

  1. 发布静态网站
  2. 实现反向代理
  3. 实现负载均衡。所谓的负载均衡是指:当同时有多个用户访问我们服务器的时候,为了减少服务器的压力,我们需要将用户引入服务器集群中较轻压力的服务器,分担较重压力服务器的负担。
    4.邮件服务器

正向代理

客户端如果要设置正向代理服务器,前提是要知道正向代理服务器的IP地址和代理程序的端口号。
正向代理是一个位于客户端和原始服务器之间的服务器,通常所说的代理服务器就是指正向代理服务器。
正向代理的用途:

  1. 访问原来无法访问的资源
  2. 可以做缓存,加速访问资源
  3. 对客户端访问授权,上网进行认证。(如:网吧上网的电脑)
  4. 代理可以记录用户访问记录,对外隐藏用户的信息

反向代理:

反向代理方式是指以代理服务器来接收internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

反向代理的作用

  1. 保证内网的安全,可以使用反向代理提供防火墙(WAF)功能,阻止web攻击。大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。一旦受到攻击,攻击的是代理服务器,而不是真正的Web服务器。

  2. 负载均衡,通过反向代理服务器来优化网站的负载。当大量客户端请求代理服务器时,反向代理可以集中分发不同用户请求给不同的web服务器进行处理请求。

小心得1:要写一层测试一层,避免出现bug无从查起。

1:dao层写好,test一下,看数据是否传出,若没,先在mysql测试sql语句。
2:写好servlet测试数据有没有输出,json格式正确与否。没有再检查!如果不知道如何Test,则看要测试的方法,需要什么参数,再寻找所需参数。

小心得2:

有时一些数据于对象属性过于复杂,难以操作,所以要将数据封装到对象内,以便于对数据的操作:
1,在dao层对三张表的连接查询,并且返回成一个Map对象
2,业务层:
.调用DAO得到一个Map对象,包含三个信息:线路,分类,商家
实例化三个对象Route, Category, Seller
使用BeanUtils将三个对象都从Map中复制属性值,其中beanUtils.populate只会复制对象中出现的属性,如果没有则不会复制。BeanUtils.populate(route,map);
调用DAO得到线路对应的图片集合
将分类,商家,图片集合设置成Route对象的属性route.setCategory(category)
返回封装好的Route对象,

3:在servlet查找到对应的数据,调用业务层,转成json对象。ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(route);
4,html()设置或获取标签内部的HTML内容。有参就是设置

小心得3:

单词拼写错误,导致时间的流逝问题\!要学会一些基本的debug!
debug技巧:在浏览器端输入对应变量的值,F12在调用函数前,可得到变量值处设置断点,然后按右右上角,进入到idea设置断点的地方,然后一行行往下,看变量值是否为空。再检查!还可以在servlet层设置断点,在浏览器上跑,跑到那一步一,转到servlet层看数据是否出来

分页多条件组合查询:DAO中查询符合条件的记录数:sql拼接

/**
 查询总记录数
 */
public int getCountByFavoriteRank(Map<String,String> condition) {
    //创建一个集合,封装占位符的值
    List<Object> list = new ArrayList<>();

    //创建SQL语句
    StringBuilder sql = new StringBuilder("select count(*) from tab_route where 1=1 ");
    //判断查询条件:如果这个键不为空,而且也不等于空字符串,就把它做为查询的条件
    String rname = condition.get("rname");
    //不为空,而且也不等于空字符串。模糊查询线路名称
    if (rname!=null && !"".equals(rname.trim())) {
        sql.append(" and rname like ?");
        list.add("%" + rname + "%");  //向集合中添加了一个真实的值
    }
    //最小值
    String startPrice = condition.get("startPrice");
    if (startPrice!=null && !"".equals(startPrice.trim())) {
        sql.append(" and price >=?");
        list.add(startPrice);
    }
    //最大值
    String endPrice = condition.get("endPrice");
    if (endPrice!=null && !"".equals(endPrice.trim())) {
        sql.append(" and price <=?");
        list.add(endPrice);
    }

    //转成数组
    Object[] args = list.toArray();

    System.out.println(sql);
    System.out.println(list);

    return template.queryForObject(sql.toString(), int.class, args);
}

/**
 收藏排行榜降序排序,显示一页数据
 @param current 当前页
 @param size 页面大小
 @param condition 封装三个查询条件
 rname = "双飞4天", startPrice="2000", endPrice="4000"
 */
public List<Route> getRoutesFavoriteRankByPage(int current, int size, Map<String,String> condition) {
    //创建一个集合,封装占位符的值
    List<Object> list = new ArrayList<>();

    //创建SQL语句
    StringBuilder sql = new StringBuilder("select * from tab_route where 1=1 ");
    //判断查询条件:如果这个键不为空,而且也不等于空字符串,就把它做为查询的条件
    String rname = condition.get("rname");
    //不为空,而且也不等于空字符串。模糊查询线路名称
    if (rname!=null && !"".equals(rname.trim())) {
        sql.append(" and rname like ?");
        list.add("%" + rname + "%");  //向集合中添加了一个真实的值
    }
    //最小值
    String startPrice = condition.get("startPrice");
    if (startPrice!=null && !"".equals(startPrice.trim())) {
        sql.append(" and price >=?");
        list.add(startPrice);
    }
    //最大值
    String endPrice = condition.get("endPrice");
    if (endPrice!=null && !"".equals(endPrice.trim())) {
        sql.append(" and price <=?");
        list.add(endPrice);
    }
    //分页功能加上
    sql.append(" order by count desc limit ?,?");
    list.add((current - 1) * size);
    list.add(size);


    //将一个集合转成Object数组
    Object[] args = list.toArray();
    System.out.println(sql);
    System.out.println(list);
    //将StringBuilder转成String。占位符传入一个Object[]数组
    return template.query(sql.toString(),new BeanPropertyRowMapper<>(Route.class), args);
}
小心得4:后台管理系统。

当dao,service,servlet层都没有错误,而jsp页面明显没有接收到servlet传过来的数据时,jst1类库无法识别!可加一句启用EL语句的话:<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>看是否有错误!当时就这个bug搞了老半天!

jsp与jQury的区别:
书写代码方式:jsp写在<%=%>或者El表达式{}中 jqury写在匿名函数中(function(){
})
jsp在页面method="post" action="route"l而在servlet中使用转发到jsp页面,而jqery使用out.println()打印到页面。

同步与异步一些区别

反射回顾:

反射的第一步永远先得到class类对象:三种方式得到

  • 方式1: 通过类名.class获得
  • 方式2:通过对象名.getClass()方法获得
  • 方式3:通过Class类的静态方法获得: static Class forName("类全名")
    • 每一个类的Class对象都只有一个。
      暴力反射:1. T newInstance(Object... initargs)
      根据指定的参数创建对象
  1. void setAccessible(true)
    设置是否取消权限检查,true取消权限检查,false表示不取消

小心得5:

${变量或者表达式},使用EL时必须先往作用域里加数据,EL表达式作用有限,1式获取数据,2,算术运算符

//得到文本框中值,去掉前后空格
var username = $(this).val().trim();

经过这几天的项目发现基础知识还需要去好好补补,在前端方面感觉很不足,有时候后端代码都可以写出来,到前端就懵逼了,接下来几天要好好补补前端方面的知识,在把这个小项目的一些功能再实现一次!干巴爹!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • IOC 控制反转容器控制程序对象之间的关系,而不是传统实现中,有程序代码之间控制,又名依赖注入。All 类的创建,...
    irckwk1阅读 1,038评论 0 0
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,444评论 0 10
  • 一. Java基础部分.................................................
    wy_sure阅读 3,882评论 0 11
  • 经典的Java面试题(第二部分),这部分主要是与Java Web和Web Service相关的面试题。 96、阐述...
    nnngu阅读 710评论 0 8
  • JSP总结(经典) day1 JSP 定义: 1)Java Server Page, Java EE 组件,本...
    java日记阅读 3,556评论 0 13