0804_shiro权限管理+微服务springcloud+周测题目

1.shiro权限管理
(1)编写Role实体类

@Entity
@Table(name = "t_role")
public class Role implements Serializable {


    private static final long serialVersionUID = -2608765352170228939L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;

    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<>(0);

    @ManyToMany(fetch = FetchType.EAGER)
    private Set<Permission> permissions = new HashSet<>(0);

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }

    public Set<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<Permission> permissions) {
        this.permissions = permissions;
    }
}

(2)编写User实体类

@ManyToMany(fetch = FetchType.EAGER)
    private Set<Role> roles = new HashSet<>(0);

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

(3)编写Permission实体类

@Entity
@Table(name = "t_permission")
public class Permission implements Serializable {

    private static final long serialVersionUID = -6266065191284242266L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String code;
    private String description;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

(4)导入shiro所需要的依赖

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

(5)实体类Role和Permission中的Id序列化设置
在这里插入图片描述
在这里插入图片描述

public static long getSerialVersionUID() {
        return serialVersionUID;
    }

(6)编写NewsRealm类

public class NewsRealm extends AuthorizingRealm {

    public void setName(String name){setName("newsRealm");}

    @Autowired
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取认证的用户数据
        User user = (User)principalCollection.getPrimaryPrincipal();
        //构造认证数据
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<Role> roles = user.getRoles();
        for (Role role:roles){
            //添加角色信息
            info.addRole(role.getName());
            for (Permission permission: role.getPermissions()){
                //添加权限信息
                info.addStringPermission(permission.getCode());
            }
        }
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken)authenticationToken;
        String username = upToken.getUsername();
        String password = new String(upToken.getPassword());
        User user = userService.checkUsers(username,password);
        if (user!=null){
            return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
        }
        return null;
    }
}

(7)编写ShiroConfiguration类

@Configuration
public class ShiroConfiguration {

    //创建realm
    @Bean
    public NewsRealm getRealm(){return new NewsRealm();}

    //创建安全管理器
    @Bean
    public SecurityManager securityManager(NewsRealm realm){
        //使用默认的安全管理器
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        //将自定义realm交给安全管理器统一调度管理
        return securityManager;
    }

    //配置shiro过滤工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        //通用配置
        shiroFilterFactory.setLoginUrl("/admin");
        shiroFilterFactory.setUnauthorizedUrl("/admin");//未授权
        /*
        * key: 请求路径
        * value: 过滤器类型
         */
        Map<String ,String > filterMap = new LinkedHashMap<>();
        filterMap.put("/admin/**","authc");

        shiroFilterFactory.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactory;
    }


    //开启shiro注解支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}

(8)编写LoginController类

@PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password,
                        HttpSession session, RedirectAttributes attributes){

//        User user = userService.checkUsers(username,password);
//        if(user!=null){
//            user.setPassword(null);
//            session.setAttribute("user",user);
//            return "admin/index";
//        }else {
//            attributes.addFlashAttribute("message","用户名或密码错误");
//            return "redirect:/admin";
//        }
        try{
            //构造登录令牌
            UsernamePasswordToken upToken = new UsernamePasswordToken(username,password);
            //获取subject
            Subject subject = SecurityUtils.getSubject();
            subject.login(upToken);
            User user = (User) subject.getPrincipal();
            session.setAttribute("user",user);
            return "admin/index";
        }catch (Exception e){
            attributes.addFlashAttribute("message","用户名或密码错误");
            return "redirect:/admin";
        }
    }

(9)界面展示
在这里插入图片描述
(10)权限管理
①编写ShiroConfiguration类

//配置shiro过滤工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        //通用配置
        shiroFilterFactory.setLoginUrl("/admin");
        shiroFilterFactory.setUnauthorizedUrl("/admin");//未授权
        /*
        * key: 请求路径
        * value: 过滤器类型
         */
        Map<String ,String > filterMap = new LinkedHashMap<>();
        filterMap.put("/admin/news","perms[user-news]");
        filterMap.put("/admin/types","perms[user-types]");
        filterMap.put("/admin/tags","perms[user-tags]");
        filterMap.put("/admin/login","anon");
        filterMap.put("/admin/**","authc");

        //设置过滤器
        shiroFilterFactory.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactory;
    }

②界面展示
在这里插入图片描述
2.微服务springcloud
(1)创建springcloud
①File→New→Module…
在这里插入图片描述
②→Spring Initializr→Next
在这里插入图片描述
③修改Group、Artifact、Java Version→Next
在这里插入图片描述
④选择如下依赖→Next
在这里插入图片描述
⑤新建一个scloud文件夹,并修改root、location
在这里插入图片描述
在这里插入图片描述
⑥成功展示
在这里插入图片描述
⑦修改pom.xml文件

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.4</version>
</dependency>

⑧修改application.properties文件名
在这里插入图片描述
⑨编写User实体类

@Table(name = "tb_user")
public class User  implements Serializable {

    private static final long serialVersionUID = -1203619350515120953L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

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

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday=" + birthday +
                ", created=" + created +
                ", updated=" + updated +
                '}';
    }
}

⑩编写UserMapper接口

@org.apache.ibatis.annotations.Mapper
public interface UserMapper extends Mapper<User> {
}

⑩①编写UserService类

@Service
public class UserService {

    @Autowired(required = false)
    private UserMapper userMapper;
    
    public User queryById(Long id){
        return this.userMapper.selectByPrimaryKey(id);
    }

}

⑩③编写UserController类

RestController
@RequestMapping("user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("{id}")
    public User queryById(@PathVariable("id") Long id){
        return this.userService.queryById(id);
    }
}

⑩④编写修改application.yml文件

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/sp_learn?useSSl=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: ******
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  type-aliases-package: com.roger.service.provider.po

(2)创建consumer Module

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
②修改application.properties文件名
在这里插入图片描述

server:
  port: 80

③编写User实体类

public class User  implements Serializable {

    private static final long serialVersionUID = -1203619350515120953L;


    private Long id;
    private String username;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

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

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday=" + birthday +
                ", created=" + created +
                ", updated=" + updated +
                '}';
    }
}

④编写UserController类

@Controller
@RequestMapping("consumer/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping
    @ResponseBody
    public User queryById(@RequestParam("id") Long id){
        User user = this.restTemplate.getForObject("http://localhost:8081/user/"+id,User.class);
        return user;
    }

}

⑤修改修改ConsumerApplication类

 //注册RestTemplate
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

(3)创建EurekaServer
①创建eureka Module
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
②修改application.properties文件名

server:
  port: 10086

spring:
  application:
    name: eureka-server #应用名称,会在Eureka中显示
eureka:
  client:
    service-url: #eurekaServer地址,现在是自己的地址,如果是集群,需要加上其他server地址
      defaultZone: http://localhost:${server.port}/eureka

③修改EurekaApplication类

@EnableEurekaServer //声明当前springboot应用是一个eureka服务中心

③界面展示
在这里插入图片描述
④修改pom.xml文件

<!-- Eureka客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

⑤修改修改application.yml文件

application:
    name: service-provider #应用名称,注册到eureka后的服务名称
    
eureka:
  client:
    service-url: #EurekaServer 地址
      defaultZone: http://localhost:10086/eureka

⑥编写ProviderApplication类

@EnableEurekaClient

⑦界面展示
在这里插入图片描述

3.周测题目
周测1(7.26)
1.String,StringBuffer,StringBuilder的区别?
String:字符串常量 。

StringBuffer 与 StringBuilder是字符缓冲变量。

StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而StringBuilder没有这个修饰,可以被认为是线程不安全的。StringBuilder 是在JDK1.5才加入的。jdk的实现中StringBuffer与StringBuilder都继承自AbstractStringBuilder。
1、String类型的字符串对象是不可变的,一旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。
2、StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,而StringBuilder不是线程安全的
3、如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。毕竟String类是通过创建临时变量来实现字符串拼接的,耗内存还效率不高,怎么说StringBuilder是通过JNI方式实现终极操作的。
4、StringBuilder和StringBuffer的“可变”特性总结如下:
(1)append,insert,delete方法最根本上都是调用System.arraycopy()这个方法来达到目的
(2)substring(int, int)方法是通过重新new String(value, start, end - start)的方式来达到目的。因此,在执行substring操作时,StringBuilder和String基本上没什么区别。
总的来说,三者在执行速度方面的比较:StringBuilder > StringBuffer > String。
参考、转载自图析:String,StringBuffer与StringBuilder的区别.
String,StringBuffer和StringBuilder的区别及使用场景.

2.String str = “i” 与 String str = new String(“i”)一样吗?
首先明白一个事,java存在一个常量池,可以用来存储字符串常量。

1 创建的字符串变量在内存中的区别
两者看似都是创建了一个字符串对象,但在内存中确是各有各的想法。

String str1= “abc”; 在编译期,JVM会去常量池来查找是否存在“abc”,如果不存在,就在常量池中开辟一个空间来存储“abc”;如果存在,就不用新开辟空间。然后在栈内存中开辟一个名字为str1的空间,来存储“abc”在常量池中的地址值。

String str2 = new String(“abc”) ;在编译阶段JVM先去常量池中查找是否存在“abc”,如果过不存在,则在常量池中开辟一个空间存储“abc”。在运行时期,通过String类的构造器在堆内存中new了一个空间,然后将String池中的“abc”复制一份存放到该堆空间中,在栈中开辟名字为str2的空间,存放堆中new出来的这个String对象的地址值。

也就是说,前者在初始化的时候可能创建了一个对象,也可能一个对象也没有创建;后者因为new关键字,至少在内存中创建了一个对象,也有可能是两个对象。

2 String类的特性
String类 是final修饰的,不可以被继承。

String类的底层是基于char数组的。

3 两个方面
1)性能效率

String类被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。例如:

String str = “hello";

str = str + "world“;

所以当上文str指向了一个String对象(内容为“hello”),然后对str进行“+”操作,str原来指向的对象并没有变,而是str又指向了另外一个对象(“hello world”),原来的对象还在内存中。

由此也可以看出,频繁的对String对象进行修改,会造成很大的内存开销。此时应该用StringBuffer或StringBuilder来代替String。

而new String()更加不适合,因为每一次创建对象都会调用构造器在堆中产生新的对象,性能低下且内存更加浪费。

2)安全性

对象都是只读的,所以多线程并发访问也不会有任何问题。

由于不可变,用来存储数据也是极为安全的。

参考、转载自: 浅谈String str = “” 和 new String()的区别.
Java的string类常量池及不可变性.

3.Java中IO流分为几种?
Java中的IO流
指的是将不同的输入输出源通过流的形式进行输入或输出的操作,流是一种抽象的描述,在程序中指的是数据的一种转移方式。

IO流的分类:
(1)按照数据的流向:
输入流、输出流
(2)按照流数据的格式:
字符流、字节流
(3)按照流数据的包装过程:
节点流(低级流)、处理流(高级流)

最基本的几种进行简单介绍:
•InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

•OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
参考、转载自: Java面试题之IO流分为几种?.
java 中 IO 流分为几种?.

4.Collection 和 Collections有什么区别?
1、java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

List,Set,Queue接口都继承Collection。
直接实现该接口的类只有AbstractCollection类,该类也只是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类。

2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
参考、转载自: Collection和Collections有什么区别?.

5.List、Set、Map之间的区别是什么?
一、数组和集合的区别:

1.数组的大小是固定的,并且同一个数组只能是相同的数据类型

2.集合的大小是不固定的,在不知道会有多少数据的情况下可使用集合。

二、集合的三种类型:list(列表)、set(集)、map(映射)

List接口和Set接口属于Collection接口,Map接口和Collection接口并列存在(同级)。

List(元素可重复性,有序性):
Set(具有唯一性,无序性):
Map(采用键值对<key,value>存储元素,key键唯一):

hashmap:底层结构是数组+链表,无序,线程不安全,效率高,允许有null(key和value都允许),父类是AbstractMap

treemap:底层结构是红黑树,有序,将数据按照key排序,默认是升序排序。

hashtable:底层结构是哈希表,无序,线程安全,效率低,不允许有null值,父类是Dictionary

参考、转载自: List、Map、Set之间的联系与区别:.

6.HashMap 和 HashTable有什么区别?
1.(同步性)HashTable的方法是同步的,HashMap不能同步。

2.(继承的父类不同)HashTable是继承自Dictionary类,而HashMap是继承自AbstractMap类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。

3.(对null key和null value的支持不同).HashTable不允许null值(key和value都不可以),HashMap允许使用null值(key和value)都可以。这样的键只有一个,可以有一个或多个键所对应的值为null。

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明。

当key为Null时,调用put() 方法,运行到下面这一步就会抛出空指针异常。因为拿一个Null值去调用方法了。

当value为null值时,Hashtable对其做了限制,运行到下面这步也会抛出空指针异常。

HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

4.(遍历方法不同)HashTable使用Enumeration遍历,HashMap使用Iterator进行遍历。

5.(初始化和扩容方式不同)HashTable中hash数组初始化大小及扩容方式不同。

Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。

创建时,如果给定了容量初始值,那么Hashtable会直接使用你给定的大小,而HashMap会将其扩充为2的幂次方大小。也就是说Hashtable会尽量使用素数、奇数。而HashMap则总是使用2的幂作为哈希表的大小。

6.计算hash值的方法不同。

Hashtable直接使用key对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数法来获得最终的位置。

HashMap为了得到元素的位置,首先需要根据元素的 Key计算出一个hash值,然后再用这个hash值来计算得到最终的位置。

HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉.例如通过h^(h>>>16)无符号位右移。

1.5 HashMap中hash函数怎么是是实现的?还有哪些 hash 的实现方式?
  1. 对key的hashCode做hash操作(高16bit不变,低16bit和高16bit做了一个异或);
  2. hash & (length-1); //通过位操作得到下标index。

还有数字分析法、平方取中法、分段叠加法、 除留余数法、 伪随机数法

(0x7FFFFFFF–最大整型数)

7.(对外提供的接口不同 )Hashtable比HashMap多提供了elements() 和contains() 两个方法。

elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。

contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
参考、转载自: HashMap和HashTable的区别.
HashMap和HashTable有什么不同?.

7.什么是Java序列化?什么情况下需要序列化?
序列化:将 Java 对象转换成字节流的过程。

反序列化:将字节流转换成 Java 对象的过程。

当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。

注意事项:

某个类可以被序列化,则其子类也可以被序列化
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
反序列化读取序列化对象的顺序要保持一致

参考、转载自: 什么是 java 序列化?什么情况下需要序列化?.

8.动态代理是什么?有哪些应用?
动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。

动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。

动态代理的应用:Spring的AOP,加事务,加权限,加日志。
参考、转载自: 详解java动态代理机制以及使用场景(一).

9.JSP 和 Servlet有什么区别?
1.Servlet是一种服务器bai端的Java应用程序,具有独立于平du台和协议的特性,可以生zhi成动态的Web页面。dao它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器响应(HTTP服务器上的数据库或应用程序)的中间层。

Servlet是位于Web服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。

2.JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计。

JSP技术使用Java编程语言编写类XML的tags和scriptlets,来封装产生动态网页的处理逻辑。网页还能通过tags和scriptlets访问存在于服务端的资源的应用逻辑。

JSP将网页逻辑与网页设计的显示分离,支持可重用的基于组件的设计,使基于Web的应用程序的开发变得迅速和容易。 JSP(JavaServer Pages)是一种动态页面技术,它的主要目的是将表示逻辑从Servlet中分离出来。

3.JSP和Servlet相同点:

JSP可以被看作一个特殊的Servlet,它只不过是对Servlet的扩展,只要是JSP能够完成的工作,使用Servlet都可以完成,例如生成动态的页面;

由于JSP页面最终要被转换成Servlet来运行,因此处理请求实际上是编译后的Servlet。

4.JSP和Servlet的擅长方便不同:

Servlet的实现方式是在java代码中嵌入HTML代码,编写和修改HTML非常不方便,所以适合做流程控制和业务逻辑的处理;

JSP实现的方式是在HTML中嵌入java代码,比较适合页面的显示。

5.JSP和Servlet内置对象不同:

Servlet中没有内置对象,JSP中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到。

10.JSP有哪些内置对象?作用分别是什么?
1.HttpServletRequet类的Request对象:代表请求对象,主要用于接受客户端通过HTTP协议连接传输服务器端的数据。

2.HttpSevletResponse类的Response对象:代表响应对象,主要用于向客户端发送数据。

3.JspWriter类的out对象:主要用于向客户端输出数据,out的基类是jspWriter

4.HttpSession类的session对象:主要用来分别保存每个月的信息与请求关联的会话;会话状态的维持是web应用开发者必须面对的问题。

5.ServletContext类的application对象:主要用于保存用户信息,代码片段的运行环境;它是一个共享的内置对象,即一个容器中的多个用户共享一个application

,故其保存的信息被所有用户所共享。

6.PageContext类的PageContext对象:管理网页属性,为jsp页面包装页面的上下文,管理对属于jsp的特殊可见部分中已经命名对象的访问,它的创建和初始化都是由容器来完成的。

7.ServletConfig类的Config对象:代码片段配置对象,标识Servlet的配置。

8.Object类的Page对象,处理jsp页面,是object类的一个实例,指的是jsp实现类的实例

9.Exception对象:处理jsp文件执行时发生的错误和异常,只有在错误页面里才使用,前提是在页面指令里要有isErrorPage=true。

11.final、finally、finalize有什么区别?try-catch-finally中哪个部分可以省略?
一、final、finally与finalize的区别
final:final是一个修饰符,可以修饰类,方法和变量。final修饰类表示类不能被其它类继承,并且该类中的所有方法都会隐式的被final修饰。final修饰方法,则该方法不能被重写,若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
finally:finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。但须注意,在某些特殊情况下,finally块是不会执行的。
finalize:finalize()是Object中定义的一个方法,也就是每个对象都有这个方法。当垃圾回收器确定不存在对该对象的更多引用时(是个垃圾),由对象的垃圾回收器调用此方法。子类重写 finalize 方法,以配置系统资源或执行其他清除,例如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。

二、try-catch-finally中哪个部分可以省略
  catch和finally可以省略其中一个。

三、try-catch-finally中try块中有return,finally还会执行吗?
会执行,当我们执行到return之后,我们不会立即返回,而是会接着执行finally块里面的代码,只有执行完,才会继续执行我们的return值。

1、不管有没有异常,finally中的代码都会执行
2、当try、catch中有return时,finally中的代码依然会继续执行
3、finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。
4、如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。
5、finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值

12.forward 和 redirect的区别?
forward和redirect是什么?

是servlet的主要两种跳转方式,forward又叫转发,redirect叫重定向

区别(地址栏,数据共享,应用场景,效率,本质,次数)

1、从地址栏显示来说:forward是服务器内部重定向,

客户端浏览器的网址不会发生变化;redirect发生一个状态码,告诉服务器去重新请求那个网址,显示的的新的网址

2、数据共享:在定向过程中forward使用的是同一个request,可以共享;redirect不可以。

3、应用场景:forward一般用于用户登录:redirect用于用户注销登录返回主页面或者跳转其他页面

4、forward效率更高

5、本质上说:forward转发是服务器上的行为,而redirect是客户端行为

6、次数:forward只有一次,redirect两次

Java语言在序列化的时候不会序列化static属性

13.简述TCP 和 UDP的区别?
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息。

优点:UDP速度快、操作简单、要求系统资源较少,由于通讯不需要连接,可以实现广播发送

缺点:UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数
据是否会正确接收,也不重复发送,不可靠。

TCP是面向连接的通讯协议,通过三次握手建立连接,通讯完成时四次挥手

优点:TCP在数据传递时,有确认、窗口、重传、阻塞等控制机制,能保证数据正确性,较为可靠。

缺点:TCP相对于UDP速度慢一点,要求系统资源较多。

14.TCP为什么要三次握手?两次不行吗?为什么?
两次握手只能保证单向连接是畅通的。
Step1 A -> B : 你好,B。
Step2 A <- B : 收到。你好,A。

这样的两次握手过程, A 向 B 打招呼得到了回应,即 A 向 B 发送数据,B 是可以收到的。
但是 B 向 A 打招呼,A 还没有回应,B 没有收到 A 的反馈,无法确保 A 可以收到 B 发送的数据。

只有经过第三次握手,才能确保双向都可以接收到对方的发送的 数据。
Step3 A -> B : 收到,B。
这样 B 才能确定 A 也可以收到 B 发送给 A 的数据。
参考、转载自: TCP 为什么三次握手而不是两次握手(正解版).

15.说一下你熟悉的设计模式?
Java中一般认为有23 种设计模式, 总体来说设计模式分为三大类:
创建型模式,共五种:
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录 模式、状态模式、访问者模式、中介者模式、解释器模式。

所谓设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。
在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中给出了三类(创建型[对类的实例化过程的抽象化]、结构型[描述如何将类或对象结合在一起形成更大的结构]、行为型[对在不同的对象之间划分责任和算法的抽象化])共23种设计模式,包括:

创建型:Abstract Factory(抽象工厂模式),Builder(建造者模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式);

结构型:Facade(门面模式),Adapter(适配器模式),Bridge(桥梁模式),Composite(合成模式),Decorator(装饰模式),Flyweight(享元模式),Proxy(代理模式);

行为型:Command(命令模式),Interpreter(解释器模式),Visitor(访问者模式),Iterator(迭代模式),Mediator(调停者模式),Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(责任链模式)。

例如:

工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理等。

适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。

模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。

参考、转载自: Java面试二(设计模式).

16.为什么要使用Spring?
spring 是一个开源的轻量级 JavaBean 容器框架。使用 JavaBean 代替 EJB ,并提供了丰富的企业应用功能,降低应用开发的复杂性。

轻量:非入侵性的、所依赖的东西少、资源占用少、部署简单,不同功能选择不同的 jar 组合
容器:工厂模式实现对 JavaBean 进行管理,通过控制反转(IOC)将应用程序的配置和依赖性与应用代码分开
松耦合:通过 xml 配置或注解即可完成 bean 的依赖注入
AOP:通过 xml 配置 或注解即可加入面向切面编程的能力,完成切面功能,如:日志,事务…的统一处理
方便集成:通过配置和简单的对象注入即可集成其他框架,如 Mybatis、Hibernate、Shiro…
丰富的功能:JDBC 层抽象、事务管理、MVC、Java Mail、任务调度、JMX、JMS、JNDI、EJB、动态语言、远程访问、Web Service…

参考、转载自: 初识Spring(为什么要使用Spring?).

17.解释一下什么是AOP?
aop 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。AOP(Aspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。

参考、转载自: 面试题思考:解释一下什么叫AOP(面向切面编程).

18.Spring常用的注入方式有哪些?
setter属性注入
构造方法注入
注解方式注入
参考、转载自: Spring常用的三种注入方式.
Spring常用的三种注入方式补充.

19.说一下Spring MVC运行流程
执行流程:
1、 用户向服务器发送请求,请求被 Spring 前端控制 Servelt DispatcherServlet 捕获(捕获)

2、 DispatcherServlet对请求 URL进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping获得该Handler配置的所有相关的对象(包括 Handler对象以及 Handler对象对应的拦截器),最后以 HandlerExecutionChain对象的形式返回;(查找 handler)

3、 DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。 提取Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller), Handler执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象(执行 handler)

4、DispatcherServlet 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver) (选择 ViewResolver)

5、通过 ViewResolver 结合 Model 和 View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回)

快速记忆技巧:

核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver,通过ViewResolver渲染视图并返回

参考、转载自: 简单讲一下 SpringMVC的执行流程?.
简单讲一下SpringMVC的执行流程?.

20.mybatis 中 #{} 和 KaTeX parse error: Expected 'EOF', got '#' at position 11: {}的区别是什么? #̲{}是预编译处理,{}是字符串替换。

(1)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。

(2)mybatis在处理时,就是把时,就是把{}替换成变量的值。

(3)使用#{}可以有效的防止SQL注入,提高系统安全性。原因在于:预编译机制。预编译完成之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。

(4)预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。
参考、转载自: Mybatis中 #{}和${}的区别.

21.简单介绍下MVC框架
MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,它把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

MVC 模式的目的是实现一种动态的程序设计,简化后续对程序的修改和扩展,并且使程序某一部分的重复利用成为可能。除此之外,MVC 模式通过对复杂度的简化,使程序的结构更加直观。软件系统在分离了自身的基本部分的同时,也赋予了各个基本部分应有的功能。专业人员可以通过自身的专长进行相关的分组:
模型(Model):程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能);
控制器(Controller):负责转发请求,对请求进行处理;
视图(View):界面设计人员进行图形界面设计。

MVC模式中三个组件的详细介绍如下:
模型(Model):用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“Model”有对数据直接访问的权力,例如对数据库的访问。“Model”不依赖“View”和“Controller”,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,由此,View 可以了解在数据 Model 上发生的改变。(比如:观察者模式(软件设计模式));
视图(View):能够实现数据有目的的显示(理论上,这不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册;
控制器(Controller):起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 Model 上的改变。
参考、转载自: MVC模式简介.
MVC框架介绍.

周测2(8.2)
1.简述rest风格
Rest (Representational State Transfer)字面上是表现层状态转移的意思,稍微深入理解一点就是从URI获得的资源在表现层进行状态的转移。

资源: 就是URI(在Rest里面又可以称为 End Point) 请求获得资源。
表现层:就是资源的表现形式,比如说以字符串方式表现,以json或者XML方式形式表现。
状态转移:就是对资源操作后的状态,比如对资源进行访问,修改,添加,删除。
如果我们开发的网站符合Rest风格设计规范,那么我们统称为Rest风格网站。
参考、转载自: 一文带你读懂Rest风格网站开发.
详解REST架构风格.

2.描述ssm框架整合的步骤
一、搭建整合环境
1.整合说明:SSM整合可以使用多种方式,本文章会选择XML + 注解的方式
2.整合的思路
3.创建数据库和表结构
4.创建maven的工程(会使用到工程的聚合和拆分的概念)
5.编写实体类,在ssm_domain项目中编写
5.编写dao接口
7.编写service接口和实现类
二、Spring框架代码的编写
1.搭建和测试Spring的开发环境
三、Spring整合SpringMVC框架
1.搭建和测试SpringMVC的开发环境
2.Spring整合SpringMVC的框架
四、Spring整合MyBatis框架
1.搭建和测试MyBatis的环境
2.Spring整合MyBatis框架
参考、转载自: SSM框架整合步骤.

3.简述Spring AOP的步骤
spring AOP的使用,分三个步骤,记住这三个步骤,AOP就不会有问题:

确定目标对象(target—>bean) 通俗的来讲就是“哪个方法需要增强,你就把他交给spring。
编写Advice通知方法 (增强代码) 就是写增强代码
配置切入点和切面 第三点的作用就是:让你的增强代码作用于你要增强的目标对象上
SpringAOP有两种实现方式:传统版本和AspectJ。具体操作都能实现业务需求,但是在这里还是希望大家能使用AspectJ,毕竟整体配置起来较为简单、轻量化,而且现在企业几乎都是AspectJ,传统的方法了解一下即可。

参考、转载自: spring AOP的使用步骤.

4.Spring Boot的核心注解是什么
启动类上面的注解是@SpringBootApplication,它是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

@ComponentScan:Spring组件扫描。

5.什么是YAML,它的优势是什么
一、YML是什么
YAML (YAML Ain’t a Markup Language)YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。可用于如: Java,C/C++, Ruby, Python, Perl, C#, PHP等。

二、YML的优点
YAML易于人们阅读。
YAML数据在编程语言之间是可移植的。
YAML匹配敏捷语言的本机数据结构。
YAML具有一致的模型来支持通用工具。
YAML支持单程处理。
YAML具有表现力和可扩展性。
YAML易于实现和使用。

参考、转载自: YML简介.

6.什么是thymeleaf,相对于传统的JSP开发模式其优势是什么
1)是什么
Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。
从代码层次上讲:Thymeleaf是一个java类库,他是一个xml/xhtml/html5的模板引擎,可以作为mvc的web应用的view层
2)传统JSP的弊端
项目目录结构繁琐
页面不简洁
jsp内置错误页面不能覆盖springboot默认的错误页面
只能打成war不能打成jar
内置的jetty服务器不支持jsp
页面响应较慢,如果数据量较多
3)优点何在
开箱即用,它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言
ymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能
有网无网的情况下模版页面都可以执行,美工的页面拿来就可以用,相对jsp减少了额外的标签,页面也更加简洁

参考、转载自: 一文搞懂Thymeleaf的使用.

7.SpringBoot、Spring、Spring MVC 有什么区别
SpringFrame
SpringFramework 最重要的特征是依赖注入。所有 SpringModules 不是依赖注入就是 IOC 控制反转。
当我们恰当的使用 DI 或者是 IOC 的时候,我们可以开发松耦合应用。松耦合应用的单元测试可以很容易的进行。

SpringMVC
Spring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。

SpringBoot
Spring 和 SpringMVC 的问题在于需要配置大量的参数。
Spring Boot 通过一个自动配置和启动的项来目解决这个问题。为了更快的构建产品就绪应用程序,Spring Boot 提供了一些非功能性特征。

简单的来说:SpringMVC和SpringBoot都是Spring家族的重要成员。Spring家族的使命就是为了简化而生。SpringMVC简化我们日常Web开发的,后来随着自身的发展,SpringMVC变得臃肿复杂,而SpringBoot则进一步简化了SpringMVC开发。
SpringBoot是基于SpringMVC无配置文件(纯Java,完全注解化)+ 内置tomcat-embed-core实现的Java Web框架。当然,SpringBoot也可以开发非Web应用,理论如此,但是实际上用SpringBoot开发非Web应用的很少。
比起SpringMVC而言,SpringBoot更高级更高端一点,SpringMVC只是SpringBoot的子集而已。SpringBoot通过引用spring-boot-starter-web依赖,整合了SpingMVC框架。
除了SpringMVC,SpringBoot还整合了其他大量的第三方框架,其原理是Maven继承依赖关系。我们在使用SpringBoot的过程中,只需要引用一个jar包,就可以通过Maven继承的方式引用到Spring-aop、Spring-beans、Spring-core、Spring-web等相关依赖。
所以,即便我们爱上了SpringBoot的无配置自动注解式编程,却也不能忘了SpringMVC的配置模式的开发,侧重点可以放在SpringBoot的学习和深入上,顺带了解下SpringMVC的原理,这才是一名优秀Java开发者的正确选择。

8.@RequestController 和 @Controller 的区别
@RestController注解相当于@ResponseBody + @Controller合在一起的作用

1)如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。
例如:本来应该到success.jsp页面的,则其显示success.
2)如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。
3)如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

例如:
1.使用@Controller 注解,
在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解

2.@RestController注解
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面

参考、转载自: @Controller和@RestController的区别?.

9.普通类和抽象类有哪些区别
抽象类不能被实例化
抽象类可以有抽象方法,抽象方法只需申明,无需实现
含有抽象方法的类必须申明为抽象类
抽象类的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类
抽象方法不能被声明为静态
抽象方法不能用 private 修饰
抽象方法不能用 final 修饰

参考、转载自: 普通类、抽象类和接口的区别.

10.session 和 cookie的区别
1、数据存放位置不同:

cookie数据存放在客bai户的浏览器du上,session数据放在服务器上。zhi
2、安全程度不同:

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、性能使用程度不同:

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

4、数据存储大小不同:

单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储与服务端,浏览器对其没有限制。
参考、转载自: cookie和session的详解和区别.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值