项目结构+实际开发中的关键实现

一般项目结构都采用 MVC 的三层结构思想

M:model 实体类 (entity):一般一个实体类对应着数据库中的一张表

V:   view    视图:显示数据,一般用于将从数据库中的数据展示到网页上

C:controller 控制层:控制器,用于处理输入,操作数据库

 

 项目一般分为:

          表现层:controller jsp 调用 service 层

          业务逻辑层:service  调用 DAO 层,并加入业务逻辑

          数据访问层:DAO(data acess object) 对数据进行 增 删 改 查

          实体类:entity  对应着数据库中的表

          工具类:Utils   工具类,一般是一些数据库连接,对数据进行处理的工具类

例: 

             

                  

注意

      1)  一般不能跨层调用,只能是  controller  ==》 service ==》dao 

      2)  层与层调用时,尽量使用接口,不要直接用实现类进行调用,提高扩展性,降低各层之间的 耦合性

   

菜单树的实现:

          当一个列表 有多级目录时,这时就需要分多次查询了,第一次查询 一级目录,再根据 一级目录 去查询 二级目录,

当所有目录都查询出来,此时就形成了一个菜单树;

     关键点: 使用 map<key , value> 存储 对应的多级目录, key: 对应菜单的 id(层级) , value:菜单的目录 

/**
* DAO层: 从数据库中查询出所有的目录
*
/

public class MenuDao {

    // 返回一个 菜单 的集合
    public static List<Menu> selectAll(){

        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet rs = null;
        List<Menu> menus = new ArrayList<>();

        try {
            conn = Utils.getConnection();
            stat = conn.prepareStatement("select * from menu");
            rs   = stat.executeQuery();

            while(rs.next()){
                Menu m = new Menu();
                m.setId(rs.getInt("id"));
                m.setName(rs.getString("name"));
                m.setPrefix(rs.getString("prefix"));
                m.setSuffix(rs.getString("suffix"));
                m.setSuffix_var(rs.getString("suffix_var"));
                m.setPid(rs.getInt("pid"));
                m.setHref(rs.getString("href"));

                menus.add(m);
            }

            return  menus;

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            Utils.close(conn,stat);
        }
    }
}

/**
 * 对菜单数据进行操作
 * 
 */
public class MenuService {

    /**
     * 找到所有 一级目录 及 子目录
     */

    public List<Menu> selectTop(){
        // 查询所有菜单对象
        List<Menu> menus = MenuDao.selectAll();
        // top用来存储一级菜单
        List<Menu> top = new ArrayList<>();
        // Map: key存储菜单的id, value存储菜单对象
        HashMap<Integer, Menu> map = new HashMap<>();

        // 遍历all,找出其中的一级菜单
        for (Menu menu : menus) {
            if(menu.getPid()==0){
                top.add(menu);
            }
            map.put(menu.getId(),menu);
        }

        //建立父子关系
        for (Menu menu : menus) {
            //根据pid找到上级目录
            Menu parent = map.get(menu.getPid());
            if(parent!=null){
                // 将找到的子目录添加进该目录中
                parent.getChildren().add(menu);
            }
        }

        return top;
    }
}

  <%-- 在jsp 页面中显示菜单--%>


        <ul>
            <%--遍历一级目录--%>
            <c:forEach items="${applicationScope.menus}" var="m1">
                <li>
                    <a href="${m1.href}" > ${m1.prefix} <span class="menu-item-parent">${m1.name}</span> ${m1.suffix} </a>
                    <c:if test="${not empty m1.children}">
                        <ul>
                                <%--遍历二级目录--%>
                            <c:forEach items="${m1.children}" var="m2">
                                <li>
                                    <a href="${m2.href}"> ${m2.prefix} <span class="menu-item-parent">${m2.name}</span>${m2.suffix}</a>
                                </li>
                            </c:forEach>
                        </ul>
                    </c:if>
                </li>
            </c:forEach>
        </ul>

 

图片验证码的实现:

          一般生成一张含有的验证码图片,然后进行登录,注册... 等操作的验证,提高程序的安全性

    目的

           1)验证操作者是否是人为操作

           2)防止表单重复提交

   关键点

     1. 生成验证码图片,并显示在浏览器上:

             1)使用 Random 随机生成 一串验证码

             2)将生成的验证码 使用 java 中的 BufferedImage 类 手动画出一张包含验证码的图片

             3)将生成的 图片对象 ImageIO.writer( 图片对象,"jepg|png", 响应字节输出流 );将 生成的图片 响应返回给浏览器

     2.  验证 表单提交的验证码 是否正确

             1)将刚开始生成的 那一串验证码(code) 存入session中的作用域(一次会话中有效)

                           req.getSession().setAttribute("code",code);

             2)  获取表单提交的验证码,与 session 中的验证码进行验证

                           String str = req.getParamater("code");

                           String code = req.getSession().getAttribute("code");

                           判断 str.equals(code) 是否 == true, 若为 true ,则验证成功,反之,则验证失败

     

/**
 * Utils : 生成验证码图片
 * @author  chen
 */
public class CheckCodeUtils {
    private static String[] arr = {"a","b","c","d","e","f","g","h","i","j","k","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"};

    //获取 4位 随机数
    public static  String random(){
        Random  r = new Random();
        StringBuilder sb = new StringBuilder(4);

        for (int i = 0; i < 4; i++) {

            //产生随机数
            int id = r.nextInt(arr.length);

            sb.append(arr[id]);
        }

        return sb.toString();
    }


    // 将 4位 的验证码生成在一张图片上
    // 输出流:将生成的图片以流的方式输出

    public static void geImage(String str, OutputStream os ){
        // 创建图片对象
        BufferedImage image = new BufferedImage(100,80,BufferedImage.TYPE_INT_RGB);

        // 获取画布
        Graphics graphics = image.getGraphics();

        // 作画
        // 设置背景色,并填充
        graphics.setColor(Color.white);
        graphics.fillRect(0,0,100,80);

        // 设置字体颜色
        graphics.setColor(Color.BLACK);

        // 设置字体
        graphics.setFont(new Font("宋体",Font.PLAIN,40));

        // 将 生成的字符串 写在画布上
        graphics.drawString(str,0,40);

        // 画上 干扰线
        graphics.drawLine(0,0,100,80);
        graphics.drawLine(0,100,0,80);

        // 用输出流输出图片
        try {
            ImageIO.write(image,"png",os);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/**
 * Controller层: 生成登录验证码
 * @author  chen
 */

@WebServlet(urlPatterns = "/check.png")
public class CheckCodeImage extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("image/png");

        // 生成一串随机数
        String random = CheckCodeUtils.random();



        // 将生成的随机数存入 session 作用域
        HttpSession session = req.getSession();
        session.setAttribute("str",random);

        // 把图片当作响应流输出 resp.getOutStream()
        CheckCodeUtils.geImage(random,resp.getOutputStream());
    }
}
<%-- 在 JSP 中展示生成的验证码图片 --%>

<section>
		<label class="label">验证码</label>
		<label class="input"> 
                 <i class="icon-append fa fa-lock"></i>
				 <img src="/check.png" 	onclick="changeImage(this)">
				 <input type="text" name="checkcode">							
		</label>
</section>

    页面显示:

                      

 

短信验证码:

       短信验证码需要调用 第三方短信服务 进行验证

      例如: 阿里云的短信服务   https://www.aliyun.com/  

                  产品和服务  => 云通信  =>  短信服务
                      1) 充值
                      2) 下载短信的sdk (软件开发包  两个 jar 包)

                           
                      3) 生成开发者的 id secret
                                管理控制台    =>  用户信息管理   =>  创建 accessKeyId   和   accessKeySecret
    
                      4) 设置短信模板和短信签名
                                短信服务=>国内消息
                                短信签名:发送者是谁
                                短信模板:规定了短信的内容

 


/**
 * 短信验证
 *
 */
public class MessageTest {

        //产品名称:云通信短信API产品,开发者无需替换
        static final String product = "Dysmsapi";
        //产品域名,开发者无需替换
        static final String domain = "dysmsapi.aliyuncs.com";


        // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
        static final String accessKeyId = "??????";
        static final String accessKeySecret = "??????";



        public static SendSmsResponse sendSms(String str) throws ClientException {

            //可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");

            //初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);

            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();


            //必填:待发送手机号
            request.setPhoneNumbers("?????");


            //必填:短信签名-可在短信控制台中找到
            request.setSignName("注册验证");


            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode("SMS_27925082"); // 尊敬的${name},您的验证码是${code},请在10分钟内输入有效


            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam("\"name\":\"chen\",\"code\":str"); //

            //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
            //request.setSmsUpExtendCode("90997");

            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            //request.setOutId("yourOutId");

            //hint 此处可能会抛出异常,注意catch
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

            return sendSmsResponse;
        }

    public static void main(String[] args) throws ClientException {

        System.out.println(CheckCode.random());

        sendSms(CheckCode.random());
    }

}

 

文件上传和下载:(以图片为例)

    1)  表单的提交格式必须是 post

    2)  必须采用复杂格式提交(多部分),不能是 参数名=参数值  的参数格式, 必须是multipart/form-data的格式   


<form action="地址" method="post" enctype="multipart/form-data">
    <input type="file" name="参数名"/>
</form>

    文件上传和下载的两个 jar 包 :

        

    

文件上传:

/**
 *      1: 导入 commons-fileupload-1.3.3.jar  和  commons-io-2.2.jar  两个jar包
 *
 *      2: 获取到一个  将上传文件存入服务器磁盘的  工具类
 *              DiskFileItemFactory factory = new DiskFileItemFactory();
 *
 *         再获取到一个 核心文件上传 的工具类
 *              ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
 *
 *      3: 获取表单提交的多部分数据
 *              List<FileItem> fileItems = servletFileUpload.parseRequest(req);
 *
 *      4: 遍历集合,得到各部分数据
 */

@WebServlet(urlPatterns = "/upload")
public class FileUpLoad extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        // 将上传文件存入服务器磁盘的一个工具类
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // 核心文件上传 工具类
        ServletFileUpload servletFileUpload = new ServletFileUpload(factory);

        try {
            // 获取表单提交的多部分数据
            List<FileItem> fileItems = servletFileUpload.parseRequest(req);

            // 遍历表单数据
            for (FileItem fileItem : fileItems) {
              
                 // 如果是普通的表单项
                if(fileItem.isFormField()){

                    System.out.println("获取参数名:"+fileItem.getFieldName());
                    System.out.println("获取参数值:"+fileItem.getString("utf-8"));

                }else{  // 文件数据(图片)
                    System.out.println("获取文件大小:"+fileItem.getSize());

                    if(fileItem.getSize()>0){

                        //将上传的文件保存到 本地磁盘 上的 G:\img 文件夹
                        fileItem.write(new File("G:\\img\\"+fileItem.getName()));
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

将上传的图片显示到页面上

  <%--在浏览器上显示上传的图片--%>  
<img  name="pic" src="images/${i.img}" height="200" width="200" >

/**
 * 显示图片
 * @author chen
 */

// 允许浏览器访问 /images 文件夹下的任意图片
@WebServlet(urlPatterns = "/images/*")
public class ProductImg extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1) 当响应的 content-type 设置为image,浏览器会显示图片
        resp.setContentType("image/jpg");


        // 把【浏览器的路径】 转换为 【服务器的磁盘路径】
        // 获取浏览器实际输入路径
        String uri = req.getRequestURI();


        // 图片的磁盘路径
        String path = "G:" + uri;


        // 如果文件不存在,返回404
        if( !new File(path).exists() ) {
            resp.sendError(404);
            return ;
        }

        // 如果存在,从文件输入流读取,向响应的输出流写
        FileInputStream is = new FileInputStream(path);
        OutputStream os = resp.getOutputStream();
        IOUtils.copy(is, os);
        IOUtils.closeQuietly(is);


    }
}

 

文件下载

// 用来显示服务器上,某个目录下任意的图片
@WebServlet(urlPatterns = "/img/*")

public class ImageServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      

        // 1) 如果要把图片进行下载操作
        resp.setContentType("application/octet-stream");
        resp.addHeader("content-disposition","attachment;filename=1.jpg");


        // 把【浏览器的路径】 转换为 【服务器的磁盘路径】
       
        // 获取浏览器实际输入路径
        String uri = req.getRequestURI(); 
      
        // 转换为 : 图片的磁盘路径
        String path = "G:" + uri;
      
        // 如果文件不存在,返回404
        if( !new File(path).exists() ) {
            resp.sendError(404);
            return ;
        }

        // 如果存在,从文件输入流读取,向响应的输出流写
        FileInputStream is = new FileInputStream(path);
        OutputStream os = resp.getOutputStream();
        
        // 利用工具类 将响应的输出流输出
        IOUtils.copy(is, os);
        IOUtils.closeQuietly(is);


    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值