假期摆烂之学习javaweb

news2024/12/23 23:47:51

Mybatis:

概念:

是一款优秀的持久层框架,用于简化 JDBC的开发:持久层也就是三层架构里面的dao层,JDBC是规范;框架就是一个半成品的软件,是一套可重复用,通用的,软件基础代码模型;

JDBC缺点:

硬编码:

1.注册驱动,获取链接

2.SQL语句

操作繁琐:

1.手动设置参数

Mybatis简化:

将硬编码字符串写到配置文件里,对于操作繁琐的代码自动完成,即免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作

MyBatis快速入门:

官网:mybatis – MyBatis 3 | 简介

1.创建模块,导入坐标;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
<!--        这里其他的日志以来会自动导入-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
            <version>1.1.7</version>
            <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        </dependencies>
</project>

2.编写核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
<!--                连接信息数据库-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///chatroomperson?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
<!--        加载SQL映射文件-->
        <mapper resource="PersonMapper.xml"/>
    </mappers>
</configuration>

4.编写SQL映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间-->
<mapper namespace="test">
    <select id="selectAll" resultType="pojo.Person">
        select * from person;
    </select>
</mapper>

5.编码

{

定义POJO类

public class Person {
    private String account;
    private String name;
    private String image;
    private String signature;
    private Date birthday;
    private String email;
    private String gender;

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getSignature() {
        return signature;
    }

    public void setSignature(String signature) {
        this.signature = signature;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Person{" +
                "account='" + account + '\'' +
                ", name='" + name + '\'' +
                ", image='" + image + '\'' +
                ", signature='" + signature + '\'' +
                ", birthday=" + birthday +
                ", email='" + email + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}

加载核心配置文件获取SqlSessionFactory对象获取该对象执行SQL语句,释放资源

public class MybatisDemo01 {
    public static void main(String []args) throws IOException {
        //加载mybatis的核心配置文件,获取SqlSessionFactory
        //如果在resources目录下面只要写一个名就可以了
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象执行sql
        SqlSession sqlSession=sqlSessionFactory.openSession();
         List<Person>persons=sqlSession.selectList("test.selectAll");
         System.out.println(persons);
         //释放资源
         sqlSession.close();

    }
}

}

Mapper代理开发:

目的:

解决原生方式中的硬编码,简化后期执行SQL

简化开发:

 1.

 2.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间-->
<mapper namespace="mapper.PersonMapper">
    <select id="selectAll" resultType="pojo.Person">
        select * from person;
    </select>
</mapper>

3.

//接口类
public interface PersonMapper {
    List<Person> selectAll();
}

 4.

public class MybatisDemo02 {

        public static void main(String []args) throws IOException {
            //加载mybatis的核心配置文件,获取SqlSessionFactory
            //如果在resources目录下面只要写一个名就可以了
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //获取SqlSession对象执行sql
            SqlSession sqlSession=sqlSessionFactory.openSession();
           //获取UserMapper接口的代理对象
            PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
            List<Person>persons=personMapper.selectAll();
            System.out.println(persons);
            //释放资源
            sqlSession.close();

        }


}

 细节:

<mappers>
<!--        加载SQL映射文件-->
<!--        <mapper resource="mapper/PersonMapper.xml"/>-->
<!--        Mapper代理方式简化包扫描-->
        <package name="mapper"/>

    </mappers>

Mybatis核心配置文件: 

enviroments:配置数据库连接环境信息,可以配置多个environment,通过default属性切换不同的environment

typeAlias:别名可以简化配置:

 <typeAliases>
        <package name=""/>
    </typeAliases>

引号里面写要连接的接口的包,然后就可以在对应的接口包里面不要写这个包了例如:

 <typeAliases>
        <package name="pojo"/>
    </typeAliases>

然后在对应的 PersonMapper的xml文件里面可以做这样的改变:

<select id="selectAll" resultType="pojo.Person">
        select * from person;
    </select>

变成 

<select id="selectAll" resultType="Person">
        select * from person;
    </select>

注意:配置各个标签时,需要遵守前后顺序 ;

配置文件增删改查和动态SQL:

MybatisX插件是一款基于IDEA快速开发插件,为效率而生

具体步骤如下:

06-MyBatis案例-环境准备_哔哩哔哩_bilibili

查询: 

步骤:

1.编写接口方法;

2.编写SQL语句;SQL映射文件;

3.执行方法测试;

注意:如果表的类里面有和表里面的字段不一样的,那么就不会自动封装,这时候就可以将查询的字段起别名使得别名和该类属性一样;但是这样的话如果有多个片段就要多次操作,所以可以通过导入一个sql片段。变成这样:

但是还有更灵活的方法:

 

<!--namespace:名称空间-->
<mapper namespace="mapper.PersonMapper">
    <resultMap id="personResultMap" type="pojo.Person">
        <result column="name" property="nameCopy"/>

    </resultMap>

    <select id="selectAll" resultMap="personResultMap">
        select * from person;
    </select>
</mapper>

查看详情:

get小知识:接口里面默认方法都是public

 mybatis里面有两种参数占位符的不同书写格式:

1.#{}替换为?,为了防止SQL注入
2.${}拼接sql语句,会存在sql注入问题
3.使用时机:
参数传递用#{}
表名或列名不固定的情况下${}会存在SQL语句注入的问题
特殊字符处理:
1.转义字符:&lt  小于号
2.CDATA区
 
-----------------------------------------------------------
</select>
    <select id="selectAccount" resultMap="personResultMap">
        select * from person where account=#{account};
    </select>
参数类型parameterType可以省略

条件查询: 

参数接收三种方式:

 <select id="selectByCondition" resultMap="personResultMap">
        select *
        from person
        where gender=#{gender}
        and name like #{nameCopy}
<!--        注意这里一定后面的要对应对象的属性名-->
    </select>
------------------------------------------------------------------------
public void selectByCondition() throws IOException {
        //接收参数
        String gender="女";
        String nameCopy="小麻子";
        //处理参数
        nameCopy=nameCopy+"%";
        Map map=new HashMap();
        map.put("gender",gender);
        map.put("nameCopy",nameCopy);
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //3。获取Mpper接口的代理对象
        PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
        //4.执行方法
        //List<Person>persons=personMapper.selectByCondition(gender,nameCopy);
       // List<Person>persons=personMapper.selectByCondition(person);
        List<Person>persons=personMapper.selectByCondition(map);
        System.out.println(persons);
        //5.释放对应的资源
        sqlSession.close();
    }

 注意:这个#号里面的属性要对应对象类里面的属性;

添加:

步骤:

1.编写接口方法:Mapper接口

void add(Person person);

2.编写SQL语句:SQL映射文件

 <insert id="add">
        insert into person(name,account,gender)
        values(#{nameCopy},#{account},#{gender})
    </insert>

3.执行方法,测试

 @Test
    public void add() throws IOException {
        //接收参数
        String gender="女";
        String nameCopy="小麻子";
        //处理参数
        nameCopy=nameCopy+"%";
        Person p=new Person();
        p.setGender(gender);
        p.setNameCopy(nameCopy);
        p.setAccount("1111111111");
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //3。获取Mpper接口的代理对象
        PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
        //4.执行方法
        //List<Person>persons=personMapper.selectByCondition(gender,nameCopy);
        // List<Person>persons=personMapper.selectByCondition(person);
        personMapper.add(p);
        //提交事务
        sqlSession.commit();
        //5.释放对应的资源
        sqlSession.close();
    }

本来代码交了之后会发现没有报错,运行成功,但是没有出现新的记录在数据库里面,这是由于mybatis默认事务提交是false,这样的话执行之后没有提交就会回滚;解决方法:(上面代码采用了第一种解决方式)

1.在释放资源之前手动提交事务;

2.在openSession的时候写入参数true;

附上:主键返回:

 对于添加的信息里面没有包括主键,但是后面还要返回主键这种情况下,可以用这个:

 <insert id="add" useGeneratedKeys="true" keyProperty="account">
        insert into person(name,account,gender)
        values(#{nameCopy},#{account},#{gender})
    </insert>

 这样可以做到在调用完add方法之后就可以得到主键值了,这里的account是我自己输入的,并且我这个是可以直接返回的,这只是做测试用例;

修改:

int update(Person person);
 <update id="update">
        update person
        set name=#{nameCopy},
        gender=#{gender}
        where account=#{account};

    </update>
  @Test
    public void update() throws IOException {
        //接收参数
        String gender="女";
        String nameCopy="小麻子+++";
        //处理参数
        nameCopy=nameCopy+"%";
        Person p=new Person();
        p.setGender(gender);
        p.setNameCopy(nameCopy);
        p.setAccount("1111111111");
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //3。获取Mpper接口的代理对象
        PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
        //4.执行方法
        //List<Person>persons=personMapper.selectByCondition(gender,nameCopy);
        // List<Person>persons=personMapper.selectByCondition(person);
        System.out.println(personMapper.update(p));
        //提交事务
        sqlSession.commit();
        //5.释放对应的资源
        sqlSession.close();
    }

删除:

删除一个:

void deleteByAccount(Person person);
<delete id="deleteByAccount">
        delete from person where account=#{account};
    </delete>

@Test
    public void deleteByAccount() throws IOException {
        //接收参数

        //处理参数
        Person p=new Person();
        p.setAccount("1111111111");
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //3。获取Mpper接口的代理对象
        PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
        //4.执行方法
        //List<Person>persons=personMapper.selectByCondition(gender,nameCopy);
        // List<Person>persons=personMapper.selectByCondition(person);
        personMapper.deleteByAccount(p);
        //提交事务
        sqlSession.commit();
        //5.释放对应的资源
        sqlSession.close();
    }

动态SQL:

多条件动态条件查询:

<if>标签:可以用if标签将会变换的SQL语句放到里面去,但是会造成一个问题,可能and语句赘余,为了解决这个,新推出一个where标签:

 </select>
    <select id="selectByCondition" resultMap="personResultMap">
        select *
        from person
        <where>
            <!--        几点要注意:首先if里面的属性要和类对象对应,而且字符串类型要注意判断空字符串,并且用!=和不带空格的单引号-->
            <if test="gender!=null and gender!=''">
                gender=#{gender}
            </if>
            <if test="nameCopy!=null and nameCopy!=''">
                and name like #{nameCopy}
            </if>

        </where>

<!--        注意这里一定后面的要对应对象的属性名-->
    </select>

 单条件的动态条件查询:

choose(when,otherwise)

</select>
    <select id="selectByConditionSingle" resultMap="personResultMap">
        select *
        from person
        where
        <choose><!--相当于switch-->
            <when test="gender!=null and gender!=''">
                gender=#{gender}
            </when>
            <when test="nameCopy!=null and nameCopy!=''">
                name like #{nameCopy}
            </when>
            
        </choose>
    </select>

但是在这种情况下,当什么都没有的时候时会报错的,这时候的格式问题还是可以用where来处理;

修改动态字段:

修改字段和普通修改字段类似,也是用if标签,但是对于格式和规范化问题,这里用的不是where而是update;

批量删除: 

批量删除参数要变成主键(一般来说)的数组

 void deleteByAccounts(@Param("accounts") String []accounts);
 <delete id="deleteByAccount">
        delete from person where account=#{account};
    </delete>
    <delete id="deleteByAccounts">
        delete from person where account in(
        <foreach collection="accounts" item="account" separator=",">
            #{account}
        </foreach>
        )
    </delete>

@Test
    public void deleteByAccounts() throws IOException {
        //接收参数
        String []accounts={"0866170880","1106231296"};
        //处理参数
        Person p=new Person();
        p.setAccount("1111111111");
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取SqlSession对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //3。获取Mpper接口的代理对象
        PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
        //4.执行方法
        //List<Person>persons=personMapper.selectByCondition(gender,nameCopy);
        // List<Person>persons=personMapper.selectByCondition(person);
        personMapper.deleteByAccounts(accounts);
        //提交事务
        sqlSession.commit();
        //5.释放对应的资源
        sqlSession.close();
    }

注意:这里由于有写可以简化的:比如在上面的xml的文件里面可以将两个括号去掉改成这样效果是一样的:

 </delete>
    <delete id="deleteByAccounts">
        delete from person where account in
        <foreach collection="accounts" item="account" separator="," open="(" close=")">
            #{account}
        </foreach>

    </delete>

如果之前的接口代码里面没有用注解改的话,一般时array数组,比如做这样的修改:

void deleteByAccounts(String []accounts);
 </delete>
    <delete id="deleteByAccounts">
        delete from person where account in
        <foreach collection="array" item="account" separator="," open="(" close=")">
            #{account}
        </foreach>
    </delete>

 

注解完成增删改查:

即将配置文件里面的SQL语句直接在接口类里面用注解完成:

  @Select("select * from person")
    List<Person> selectAll();

但是这样会导致在配置文件处理的东西就会失效,所以说注解适合处理比较简单的SQL语句; 

过滤器:

概念:

把对资源的请求拦截下来

过滤器的快速入门:

 1.定义类,实现Filter接口,并重写其所有方法

package webtest.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;

import java.io.IOException;
@WebFilter("/*")
public class FilterDemo implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo...");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

2.配置拦截资源的路径,在类定义上@WebFilter注解,这里一定要注意是@WebFilter注解,别搞错了,不然会一直拦截不了;

3.在doFilter方法中输出一句话,并放行        

执行流程:

对于web资源和浏览器的交互,中间如果有一个过滤器的话,有这样的执行流程:

先是服务器向web资源请求数据,然后经过过滤器处理,也就是执行过滤器doFilter方法前面的代码,然后访问资源里面的数据,之后再执行过滤器后面的代码;

Filter拦截路径的配置:

过滤器链:

如果有多个过滤器,对于过滤器的执行顺序,按照类名的字符串的自然排序来进行的;

执行顺序和这样的顺序一样:

Listener:

 练习:

1.定义类,实现ServletContextListener接口

2.在类上添加@WebListener注解

@WebListener
public class LoaderListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("初始化。。。");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

RBAC模型:

一种权限控制的数据库表设计(...)

05_RBAC_菜单管理案例_需求介绍_数据库设计_尚学堂_哔哩哔哩_bilibili

会话跟踪技术:

概念:

一种维护浏览器状态的方法,服务器需要识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求中共享数据(HTTP是无状态的,每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内数据共享)

实现方式:

客户端会话跟踪技术:Cookie

服务端会话跟踪技术:Session

Cookie:

Cookie基本使用:

发送:

获取:

Cookie原理:

 Cookie存活时间:

默认情况下,存活时间在浏览器内存中,当浏览器关闭,内存释放则销毁

Cookie存储中文:

Cookie不能直接存储中文:

如需储存,则进行URL编码的转码;

Session:

Session基本使用:

 HttpSession session= req.getSession();
        session.setAttribute("username","zs");
 HttpSession session=req.getSession();
            Object username=session.getAttribute("username");
            System.out.println(username);

Session原理:

 Session是基于Cookie实现的

 Session钝化、活化:

钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中

活化:再次启动服务器后,从文件加载数据到Session中;

Session销毁:

默认情况下,无操作,30分钟自动销毁,但是可以配置:

调用Session对象的invalidate方法也可以销毁;

Cookie和Session的区别:

储存位置:Cookie是将数据存储在客户端,Session将数据存储在服务器端;

安全性:Cookie不安全,Session安全

数据大小:Cookie最大3KB,Session无大小限制

存储时间:Cookie可以长期储存,Session默认三十分钟

服务器性能:Cookie不占服务器资源,Session占用服务器资源

Response和Request:

基本认识:

request获取请求对象:

response设置请求对象:

request继承体系:

tomcat创建request对象 ,创建实现类;

request获取请求数据:

 请求头:

请求体:

 

 request用通用方式获取请求参数:

 示例代码:

 Map<String,String[]>map= req.getParameterMap();
        for(String key:map.keySet())
        {
            System.out.println(key+":");
            //获取值
            String[]values=map.get(key);
            for (String value:values)
            {
                System.out.println(value+"");
            }

        }
        System.out.println("------------------------------------------------------------");
        //根据key获取参数值数组,
        String[] hobbies=req.getParameterValues("hobby");
        for(String hobby:hobbies)
        {
            System.out.println(hobby);
        }
        //根据key获取参数值:
        String username=req.getParameter("username");
        System.out.println(username);
    }

 请求方式解决中文乱码问题:

post解决方式:

get解决方式:

乱码原因:

解决方法:虽然两个程序的编解码方式不同,但是底层的字节数组是一样的,可以将后面的带的乱码的数据按相应的规则解码成相应的字节数组,然后再转换成汉字字符串;

 String username=req.getParameter("username");
        System.out.println(username);
        //编码成字节数组
        byte[]bytes=username.getBytes(StandardCharsets.ISO_8859_1);
        //解码成字符串
        username=new String(bytes,StandardCharsets.UTF_8);
        System.out.println(username);

request请求转发: 

 请求转发的特点:

浏览器地址栏路径不发生变化;

只能转发到当前服务器的内部资源;

一次请求,可以在转发的资源间使用request共享数据

Response设置响应数据方法:

Response重定向:

一种资源跳转方式,

//重定向
            //方法一:
            //设置响应状态码 302
            //resp.setStatus(302);
            //设值响应头
            //注意:这里路径要加上虚拟目录,默认虚拟目录是项目名
            //resp.setHeader("location","/web-demo/demo02");
            //方法二:
            resp.sendRedirect("/web-demo/demo02");

重定向特点: 

浏览器地址栏路径发生变化

可以重定向道任意位置的资源(服务器内部,外部均可)

两次请求,不能再多个资源使用request共享数据

资源路径问题:

浏览器使用:需要加虚拟目录(项目访问路径)

服务端使用:不需要加虚拟目录

虚拟目录可以动态配置:

所以可以动态获取虚拟目录:getContextPath方法

 Response响应数据:

响应字符数据:

resp.setContentType("text/html;charset=utf-8");
           //1.获取字符输出流
            PrintWriter writer= resp.getWriter();
            writer.write("你好");
            writer.write("<h1>你好</h1>");

响应字节数据:

 //读取文件
            FileInputStream fileInputStream=new FileInputStream("D://a.jpg");
            // 获取response字节输出流
            ServletOutputStream os=resp.getOutputStream();

            //完成流的copy
//            byte[]buff=new byte[1024];
//            int len=0;
//            while((len=fileInputStream.read(buff))!=-1)
//            {
//                os.write(buff,0,len);
//            }
//
//            fileInputStream.close();
            IOUtils.copy(fileInputStream,os);

idea模板创建servlet:

 点击Settings,Editor中的File and Code Templates,选择Other选框:Web里面Java Code Templates里面的Servlet Annotated Class;

MVC模式和三层架构:

mvc: 

分层开发的模式
好处:

职责单一,互不影响;

有利于分工协作:

有利于组件重用:

三层架构:

 

  mvc和三层架构关系:

假期结束了,又要好好学习了。。。、

任何事情在尘埃落定之前都是未知的 付出不一定跟收获成正比 但尽全力去做是绝对不会错的 哪怕做不好也没关系 就是不要在开始之前就说我不行 这很重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/982556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python中的异常处理3-1

Python中的异常指的是语法上没有错误&#xff0c;但是代码执行时会导致错误的情况。 1 抛出异常 在图1所示的代码中&#xff0c;要求用户输入一个数字&#xff0c;该代码在语法上没有错误。 图1 出现异常的代码 但是运行该代码之后&#xff0c;如果用户输入的是数字&#xf…

反转字符串 反转字符串 || 反转字符串 |||

思想总结&#xff1a;首先将字符串转变为字符数组&#xff0c;再进行遍历并反转字符。 1.反转字符串 代码&#xff1a; class Solution {public void reverseString(char[] s) {reverse(s,0,s.length); //左闭右开}public static void reverse(char[] ch,int i,int j) { 翻转函…

易基因:MLL1/DNA低甲基化介导子宫肌层干细胞发育重编程的表观遗传机制|组学研究

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 子宫肌瘤&#xff08;uterine fibroids&#xff0c;UF&#xff09;是生殖系统最常见的良性肿瘤&#xff0c;也是子宫切除手术最常见的指征。尽管患病率很高&#xff0c;但子宫肌瘤的确切…

第6章 内核模块符号导出实验(iTOP-RK3568开发板驱动开发指南 )

在上一小节中&#xff0c;给大家讲解了驱动模块传参实验&#xff0c;使用insmod命令加载驱动时可以进行参数的传递&#xff0c;但是每一个内核模块之间是相互独立的&#xff0c;那模块间的符号传递要怎样进行呢&#xff0c;让我们带着疑问来进行本章节的学习吧&#xff01; 6.…

安森美LM317全系列低压差线性稳压器(LDO)多种不同封装类型 高性能更可靠

低压差线性稳压器&#xff08;LDO&#xff09;&#xff0c;是指一种具有恒定电流输出电压的装置&#xff0c;主要由输入变压器、整流器、输出变压器三部分构成&#xff0c;工业原理为将输入的交流电压经过整流、滤波后得到直流输出电压&#xff0c;再经过控制元件和开关器件将稳…

前端 JS 经典:上传文件

重点&#xff1a;multipart/form-data 后端识别上传类型必填 1. form 表单上传 <!-- enctype"multipart/form-data" 这个必填 --> <form action"http://127.0.0.1:8080/users/avatar" method"post" enctype"multipart/form-data…

Vue框架--Vue条件渲染

这里重点讲述Vue提供的两个指令:v-show和v-if(v-else-if/v-else)。

C 风格文件输入/输出 (std::fflush)(std::fwide)(std::setbuf)(std::setvbuf)

文件访问 将输出流与实际文件同步 std::fflush int fflush( std::FILE* stream ); 对于输出流&#xff08;和最近操作为输出的更新流&#xff09;&#xff0c;将来自 stream 缓冲区的未写入数据写入关联的输出设备。 对于输入流&#xff08;和最近操作为输入的更新流&…

实在智能牵手埃林哲,“TARS-RPA-Agent+云时通”双剑合璧共推企业数字化转型

近日&#xff0c;《数字中国建设整体布局规划》进一步明确了数字化发展的方向和节奏&#xff0c;对企业数字化建设提出了新要求。回看过去几十年&#xff0c;信息化建设如火如荼&#xff0c;各类IT系统如雨后春笋般涌现&#xff0c;系统的自动化操作及系统间数据交互共享等需求…

std::make_shared和new初始化智能指针的区别

先看代码&#xff1a; class Base {public:Base(int num):a(num) {std::cout << "Base() construct" << std::endl;}~Base() {std::cout << "Base() deconstruct" << std::endl;}int Get() {return a;}private:int a; };void tes…

微信小程序的高校教室自习室占座预约系统java+uniapp

教室预约系统的系统项目的概述设计分析&#xff0c;主要内容有平台的具体分析&#xff0c;进行数据库的是设计&#xff0c;数据采用mysql数据库&#xff0c;并且对于系统的设计采用比较人性化的操作设计&#xff0c;对于系统出现的错误信息可以及时做出处理及反馈。 基于教室预…

Java 复习笔记 - 面向对象进阶篇

文章目录 一&#xff0c;Static&#xff08;一&#xff09;Static的概述&#xff08;二&#xff09;静态变量&#xff08;三&#xff09;静态方法&#xff08;四&#xff09;工具类&#xff08;五&#xff09;static的注意事项 二&#xff0c;继承&#xff08;一&#xff09;继…

电脑黑屏只有鼠标箭头?4个正确处理方法记得收藏!

“我刚刚在用电脑办公呢&#xff0c;突然之间电脑就黑屏了&#xff0c;只剩下一个鼠标箭头。这是什么原因引起的呢&#xff1f;怎么解决电脑黑屏的问题呀&#xff1f;求解答&#xff01;” 不知道朋友们有没有遇到过在使用电脑时&#xff0c;突然电脑就黑屏了并且只剩下鼠标箭头…

CMS 三色标记【JVM调优】

文章目录 1. 垃圾回收器2. CMS 原理3. 三色标记算法 1. 垃圾回收器 ① Serial&#xff1a;最原始的垃圾回收器&#xff0c;用于新生代&#xff0c;是单线程的&#xff0c;GC 时需要停止其它所有的工作&#xff0c;算法简单&#xff0c;但它只能在内存较小时勉强使用&#xff1b…

光栅和矢量图像处理:Graphics Mill 11.4.1 Crack

Graphics Mill 是适用于 .NET 和 ASP.NET 开发人员的最强大的成像工具集。它允许用户轻松向 .NET 应用程序添加复杂的光栅和矢量图像处理功能。 光栅图形 加载和保存 JPEG、PNG 和另外 8 种图像格式 调整大小、裁剪、自动修复、色度键和 30 多种其他图像操作 可处理任何尺寸&am…

C语言深入理解指针(非常详细)(四)

目录 字符指针变量数组指针变量数组指针变量是什么数组指针变量怎么初始化 二维数组传参的本质函数指针变量函数指针变量的创建函数指针变量的使用代码typedef关键字 函数指针数组转移表 字符指针变量 字符指针在之前我们有提到过&#xff0c;&#xff08;字符&#xff09;&am…

ABB MPRC086444-005数字输入模块

ABB MPRC086444-005 是一款数字输入模块&#xff0c;通常用于工业自动化和控制系统中&#xff0c;用于接收和处理数字信号。以下是这种类型的数字输入模块通常可能具备的一般功能和特点&#xff1a; 数字输入接口&#xff1a;MPRC086444-005 模块通常配备多个数字输入通道&…

Android扫码连接WIFI实现

0&#xff0c;目标 APP中实现扫WIFI分享码自动连接WIFI功能 1&#xff0c;前提条件 设备需要有个扫码器&#xff08;摄像头拍照识别也行&#xff09;&#xff0c;APP调用扫码器读取WIFI连接分享码。 2&#xff0c;增加权限 在AndroidManifest.xml中增加权限 <uses-permissi…

PyTorch深度学习实战(14)——类激活图

PyTorch深度学习实战&#xff08;14&#xff09;——类激活图 0. 前言1. 类激活图1.1 基本概念1.2 类激活图生成 2 数据集分析3 使用 PyTorch 生成 CAM小结系列链接 0. 前言 我们已经能够构建性能优异的神经网络模型&#xff0c;但对我们而言&#xff0c;卷积神经网络的决策过…

嵌入式Linux驱动开发(LCD屏幕专题)(一)

一、LCD简介 总的分辨率是 yres*xres。 1.1、像素颜色的表示 以下三种方式表示颜色 1.2、如何将颜色数据发送给屏幕 每个屏幕都有一个内存&#xff08;framebuffer&#xff09;如下图&#xff0c;内存中每块数据对用屏幕上的一个像素点&#xff0c;设置好LCD后&#xff…